/*
   * Copyright (C) 2001-2003, CompHEP Collaboration
   *------------------------------------------------------
   * $Id: colorVector.c,v 1.4 2003/06/25 18:46:42 kryukov Exp $
   *
   * $Log: colorVector.c,v $
   * Revision 1.4  2003/06/25 18:46:42  kryukov
   * *** empty log message ***
   *
   * Revision 1.3  2003/04/22 09:01:20  kryukov
   * Apply indent to improve readability of files
   *
   * Revision 1.2  2003/04/20 17:55:02  kryukov
   * Clean up warnings during make
   *
 */
#include <math.h>
#include "chep_crt/include/crt_util.h"
#include "getmem/include/getmem.h"

#include "symb/include/colorVector.h"
#include "symb/include/cweight_old.h"
#include "symb/include/cweight.h"
#include "symb/include/process.h"
#include "symb/include/diaprins.h"

#define TEST

#define DIV(a,b) ((a)>0. ? ((b)>0. ?  floor((a)/(b))   : -floor(-(a)/(b))) :\
                           ((b)>0. ?  -floor(-(a)/(b)) : floor((a)/(b))   ) )
#define REST(a,b)  ((a)-DIV(a,b)*(b))

static void 
reducec (double *l1, double *l2)
{
  double c, i1, i2;

  i1 = fabs (*l1);
  i2 = fabs (*l2);
  if (i2 > i1)
    {
      c = i1;
      i1 = i2;
      i2 = c;
    }
  while (i2 != 0)
    {
      c = i2;
      i2 = REST (i1, i2);
      i1 = c;
    }
  (*l1) = DIV (*l1, i1);
  (*l2) = DIV (*l2, i1);
}

static rat 
radd (int sign, rat a, rat b)
{
  rat r, r1, r2;

  r1 = a;
  r2 = b;

  reducec (&r1.d, &r2.d);

  r.n = r1.n * r2.d + sign * r2.n * r1.d;
  r.d = a.d * r2.d;

  reducec (&r.n, &r.d);

  if (fabs (r.n / r.d) < 1.e-10)
    {
      r.n = 0;
      r.d = 1;
    }

  return r;
}

#if 0
static rat 
rmult (rat a, rat b)
{
  rat r;

  reducec (&a.n, &b.d);
  reducec (&a.d, &b.n);

  r.n = a.n * b.n;
  r.d = a.d * b.d;

  return r;
}
#endif

static rat 
rdiv (rat a, rat b)
{
  rat r;

  reducec (&a.n, &b.n);
  reducec (&a.d, &b.d);

  r.n = a.n * b.d;
  r.d = a.d * b.n;

  if (r.d < 0)
    {
      r.d = -r.d;
      r.n = -r.n;
    }

  return r;
}

#if 0
static int 
rcomp (rat a, rat b)
{
  double r = (double) a.n / (double) a.d - (double) b.n / (double) b.d;
  if (r == 0)
    return 0;
  if (r > 0)
    return 1;
  if (r < 0)
    return -1;
  fprintf (stderr, "***** rcomp: End reach. No int val. !?\n");
}
#endif

#if 0
static void 
colorMaxtixDiagonalization (int dim, rat * matrix, int *nvect, rat ** vectors)
{

#define A(x,y) matrix[ q[(x)]<=q[(y)] ?  \
           q[(y)]*(q[(y)]+1)/2 + q[(x)] : q[(x)]*(q[(x)]+1)/2 + q[(y)] ]

#define B(x,y) matrix[ x<=y ? (y)*((y)+1)/2 + (x) : (x)*((x)+1)/2 + (y)]


  int i, j, dim1 = dim + 1, count = 0;
  int *q = (int *) m_alloc (dim * sizeof (int));	/* matrix index */
  rat *vv;

  for (i = 0; i < dim; i++)
    q[i] = i;

  *vectors = NULL;		/* resulting vector set init        */
  *nvect = 0;

#ifdef TEST
  for (i = 0; i < dim; i++)
    {
      for (j = 0; j <= i; j++)
	printf ("(%0.f,%0.f)", B (i, j).n, B (i, j).d);
      printf ("\n");
    }
#endif


  while (1)
    {
      rat amax = A (0, 0);
      int imax = 0;
      int N = dim - (*nvect);

      if (dim > 20)
	informline (count++, dim);

      if (!N)
	break;
      for (i = 0; i < N; i++)
	if (rcomp (amax, A (i, i)) == -1)
	  {
	    amax = A (i, i);
	    imax = i;
	  }
      if (amax.n == 0)
	break;
      *vectors = re_alloc (*vectors, (*nvect + 1) * (dim1) * sizeof (rat));
      vv = (*vectors) + (dim1) * (*nvect);
      vv[0] = A (imax, imax);	/*norma */
      for (i = 0; i < dim; i++)
	vv[1 + q[i]] = A (i, imax);

      (*nvect)++;

      for (i = 0; i < N; i++)
	for (j = 0; j <= i; j++)
	  A (i, j) = radd (-1, A (i, j), rdiv (rmult (vv[1 + q[j]], vv[1 + q[i]]), vv[0]));

#ifdef TEST
      printf ("\n line %d\n", q[imax]);
      for (i = 0; i < dim; i++)
	{
	  for (j = 0; j <= i; j++)
	    printf ("(%0.f,%0.f)", B (i, j).n, B (i, j).d);
	  printf ("\n");
	}
#endif
      j = q[imax];
      q[imax] = q[N - 1];
      q[N - 1] = j;		/* swap imax --- N-1 */

    }
  if (dim > 20)
    informline (dim + 1, dim);
  free (q);
}
#endif

#define C_BASIS

extern void 
generateColorVectors (vamplExt * ans, int *nvect, rat ** c_vectors)
{
  vamplExt *ans1, *ans2;
  int i, j, ntot, ii, jj;
  rat *c_matrix;
#ifdef TEST
  double *c_matrix2;
#endif

#ifdef C_BASIS
  int colors[MAXINOUT];
  int *chains;
  int pow, nc;
  int l;
  long *num1, *num2, *den1, *den2;

  for (i = 0; i < nin + nout; i++)
    {
      colors[i] = prtclbase[
			     ans->Ampl.vertlist[ans->Ampl.outer[i].vno][ans->Ampl.outer[i].edno].partcl
			     - 1].cdim;
    }

  for (i = 0; i < nin + nout; i++)
    printf ("%d ", colors[i]);
  printf ("\n");

  infCbases (nin + nout, colors, &nc, &pow, &chains);

  printf ("pow=%d, nc=%d\n chains\n", nc, pow);
  l = 0;

  for (i = 0; i < pow; i++)
    {
      for (j = 0; j < nc; j++)
	{
	  printf ("(%d ", 1 + chains[l++]);
	  printf ("%d) ", 1 + chains[l++]);
	}
      printf ("\n");
    }

  num1 = malloc (pow * sizeof (long));
  den1 = malloc (pow * sizeof (long));

  num2 = malloc (pow * sizeof (long));
  den2 = malloc (pow * sizeof (long));

#endif

  for (ntot = 0, ans1 = ans; ans1; ans1 = ans1->next)
    if (ans1->status >= 0)
      ntot++;
  c_matrix = (rat *) m_alloc (sizeof (rat) * ntot * (ntot + 1) / 2);

  for (ans1 = ans, ii = 0; ans1; ans1 = ans1->next)
    if (ans1->status >= 0)
      {
	for (ans2 = ans, jj = 0; jj <= ii; ans2 = ans2->next)
	  if (ans2->status >= 0)
	    {
	      vcsect vcs;
	      vcs.sizel = ans1->Ampl.size;
	      vcs.sizet = vcs.sizel + ans2->Ampl.size;
	      for (i = 0; i < vcs.sizel; i++)
		{
		  vcs.valence[i] = ans1->Ampl.valence[i];
		  for (j = 0; j < vcs.valence[i]; j++)
		    vcs.vertlist[i][j] = ans1->Ampl.vertlist[i][j];
		}
	      for (; i < vcs.sizet; i++)
		{
		  vcs.valence[i] = ans2->Ampl.valence[i - vcs.sizel];
		  for (j = 0; j < vcs.valence[i]; j++)
		    vcs.vertlist[i][j] = ans2->Ampl.vertlist[i - vcs.sizel][j];
		}
	      for (i = vcs.sizel; i < vcs.sizet; i++)
		for (j = 0; j < vcs.valence[i]; j++)
		  {
		    vcs.vertlist[i][j].link.vno += vcs.sizel;
		    vcs.vertlist[i][j].partcl =
		      prtclbase[vcs.vertlist[i][j].partcl - 1].anti;
		  }

	      for (i = 0; i < ans1->Ampl.outno; i++)
		{
		  int i1 = ans1->Ampl.outer[i].vno;
		  int j1 = ans1->Ampl.outer[i].edno;
		  int i2 = ans2->Ampl.outer[i].vno + vcs.sizel;
		  int j2 = ans2->Ampl.outer[i].edno;
		  vcs.vertlist[i1][j1].link = ans2->Ampl.outer[i];
		  vcs.vertlist[i1][j1].link.vno += vcs.sizel;
		  vcs.vertlist[i2][j2].link = ans1->Ampl.outer[i];
		}

#ifdef C_BASIS
	      {
		rat sum, term;
		vampl left, right;

		decompose (vcs, &left, &right);

		c_basis_coef (&left, pow, nc, chains, num1, den1);
		c_basis_coef (&right, pow, nc, chains, num2, den2);

		sum.d = 1;
		sum.n = 0;
		for (i = 0; i < pow; i++)
		  {
		    term.n = num1[i] * num2[i];
		    term.d = den1[i] * den2[i];
		    sum = radd (1, sum, term);
		  }

		term.d = 1;
		term.n = 1;
		for (i = 0; i < nc; i++)
		  term.n *= 3;
		for (i = 0; i < nin + nout; i++)
		  if (colors[i] == 8)
		    term.d *= 2;
		for (i = 0; i < ans2->Ampl.size; i++)
		  {
		    int n8 = 0;
		    for (j = 0; j < ans2->Ampl.valence[i]; j++)
		      if (8 == prtclbase[ans2->Ampl.vertlist[i][j].partcl - 1].cdim)
			n8++;
		    if (n8 == 3)
		      term.n *= -1;
		  }
		sum = rdiv (sum, term);
		cwtarg (&vcs);
/*   if(sum.n!=vcs.clrnum || sum.d!=vcs.clrdenum) */
		{		/*int n,d; */
		  for (i = 0; i < vcs.sizet; i++)
		    for (j = 0; j < vcs.valence[i]; j++)
		      {
			vcs.vertlist[i][j].nextvert.vno = vcs.vertlist[i][j].link.vno + 1;
			vcs.vertlist[i][j].nextvert.edno = vcs.vertlist[i][j].link.edno + 1;
		      }
		  for (i = 0; i < vcs.sizet; i++)
		    for (j = vcs.valence[i]; j < 4; j++)
		      vcs.vertlist[i][j].nextvert.vno = nullvert;
		  writeTextDiagram (&vcs, 0, '!', stdout);
		  printf ("sum=(%d %d)\n", (int) sum.n, (int) sum.d);

		  for (i = 0; i < pow; i++)
		    printf ("%d/%d ", (int) num1[i], (int) den1[i]);
		  printf ("\n");
		  for (i = 0; i < pow; i++)
		    printf ("%d/%d ", (int) num2[i], (int) den2[i]);
		  printf ("\n");

		  printf ("(%d %d)\n", (int) vcs.clrnum, (int) vcs.clrdenum);
		  /* printCsDiagram(&vcs); */
/*      exit(55); */
		}
	      }
#endif


#ifdef CHECK_NEW_cwtarg
	      cwtarg_old (&vcs);
	      n = vcs.clrnum;
	      d = vcs.clrdenum;

	      cwtarg (&vcs);
	      printf ("(%d %d) (%d %d)\n", n, vcs.clrnum, d, vcs.clrdenum);
	      if (n != vcs.clrnum || d != vcs.clrdenum)
		exit (77);
	    }
#endif

	for (i = vcs.sizel; i < vcs.sizet; i++)
	  {
	    int n8 = 0;
	    for (j = 0; j < vcs.valence[i]; j++)
	      if (prtclbase[vcs.vertlist[i][j].partcl - 1].cdim == 8)
		n8++;
	    if (n8 == 3)
	      vcs.clrnum *= -1;
	  }

	c_matrix[ii * (ii + 1) / 2 + jj].n = vcs.clrnum;
	c_matrix[ii * (ii + 1) / 2 + jj].d = vcs.clrdenum;
	if (ntot > 20)
	  informline (ii * (ii + 1) / 2 + jj, ntot * (ntot + 1) / 2);

	jj++;
      }
  ii++;
}
if (ntot > 20)
  informline (ntot * (ntot + 1) / 2 + 1, ntot * (ntot + 1) / 2);

#ifdef TEST
c_matrix2 = (double *) m_alloc (sizeof (rat) * ntot * (ntot + 1) / 2);
for (i = 0; i < ntot * (ntot + 1) / 2; i++)
  c_matrix2[i] = c_matrix[i].n / c_matrix[i].d;
#endif

#ifdef TEST_

colorMaxtixDiagonalization (ntot, c_matrix, nvect, c_vectors);

{
  int k;
  double amax = 0;

  printf ("Number of vertors= %d\n", *nvect);

  for (k = 0; k < *nvect; k++)
    {
      rat *cv = (*c_vectors) + k * (ntot + 1);
      for (i = 0; i <= ntot; i++)
	printf (" %.0f/%.0f ", cv[i].n, cv[i].d);
      if (cv[0].n * cv[0].d <= 0)
	printf ("Vector has a  negative norm");
      printf ("\n");
    }

  for (i = 0; i < ntot * (ntot + 1) / 2; i++)
    if (c_matrix[i].n)
      {
	printf ("Color Matrix is not zero!\n");
	break;
      }


  for (i = 0; i < ntot; i++)
    for (j = 0; j <= i; j++)
      {
	for (k = 0; k < *nvect; k++)
	  {
	    rat *cv = (*c_vectors) + k * (ntot + 1);
	    c_matrix2[i * (i + 1) / 2 + j] -=
	      cv[i + 1].n * cv[j + 1].n * cv[0].d / (cv[i + 1].d * cv[j + 1].d * cv[0].n);
	  }
      }
  for (i = 0; i < ntot * (ntot + 1) / 2; i++)
    if (amax < fabs (c_matrix2[i]))
      amax = fabs (c_matrix2[i]);
  printf ("The error of diagonalization=%e\n", amax);
  free (c_matrix2);
}
#endif
free (c_matrix);
}
