/*
  K M Briggs 2004 Sep 03, 05

*/

#include "fps.h"

void readA81(fps_t A81, int n) {
  int i,j;
  mpq_t w;
  FILE *f=fopen("../graph-theory/A81.dat","r");
  mpq_init(w);
  printf("reading ../graph-theory/A81.dat...\n");
  for (i=1; i<=1000; i++) {
    fscanf(f,"%d",&j);
    mpq_inp_str(w,f,10);
    fps_setterm(A81,w,i);
  }
  mpq_clear(w);
  fclose(f); 
}

void getA81_old(fps_t A81, int n) {
  int i;
  mpq_t p;
  fps_t s,t,onemx;
  mpq_init(p);
  s=fps_init(n);
  t=fps_init(n);
  onemx=fps_init(n);
  fps_zero(A81); fps_set_z(A81,1,1); // A=x
  for (i=1; i<=n; i++) {
    fps_zero(onemx); fps_set_z(onemx,0,1); fps_set_z(onemx,i,-1); // onemx=1-x^i
    fps_getterm(p,A81,i);
    fps_powq(t,onemx,p);
    fps_div(s,A81,t);
    fps_set(A81,s);
  }
  mpq_clear(p);
  fps_clear(onemx);
  fps_clear(t);
  fps_clear(s);
}

void getA81(fps_t A81, int n) {
  int d,k,j;
  mpq_t s1,s2,p;
  mpq_init(p);
  mpq_init(s1);
  mpq_init(s2);
  fps_zero(A81);
  fps_set_z(A81,1,1); // A=x
  for (j=2; j<=n; j++) {
    mpq_set_ui(s2,0,1);
    for (k=1; k<=j; k++) {
      fps_getterm(s1,A81,1);
      for (d=2; d<=k; d++) if (k%d==0) {
        fps_getterm(p,A81,d);
        scalar_mulby_ui(p,d)
        mpq_add(s1,s1,p);
      }
      fps_getterm(p,A81,j-k);
      mpq_mul(p,p,s1);
      mpq_add(s2,s2,p);
    }
    scalar_divby_ui(s2,j-1)
    fps_setterm(A81,s2,j);
  }
  mpq_clear(p);
  mpq_clear(s1);
  mpq_clear(s2);
}

void getA27852(fps_t A27852, fps_t A81) {
  fps_t t1,t2;
  t1=fps_init(fps_len(A81));
  t2=fps_init(fps_len(A81));
  fps_mul(t1,A81,A81);
  fps_space(t2,A81,2);
  fps_add(t1,t1,t2);
  fps_div_si(A27852,t1,2);
  fps_clear(t2);
  fps_clear(t1);
}

void getA68051_old(fps_t A68051, fps_t A81) {
  int k,n=fps_len(A81);
  fps_t sum,num,t1,t2,t3;
  sum=fps_init(n);
  fps_zero(sum);
  num=fps_init(n);
  t1=fps_init(n);
  t2=fps_init(n);
  t3=fps_init(n);
  for (k=1; k<=n; k++) {
    fps_space(t1,A81,k);
    fps_neg(t1,t1);
    fps_setterm_i(t1,1,0); // t1=1-A81(x^k)
    fps_log(t2,t1);        // t2=log(1-A81(x^k))
    fps_mul_si(t2,t2,phi(k));
    fps_div_si(t1,t2,k)  ; // t1=(phi(k)/k)*log(1-A81(x^k))
    fps_add(sum,sum,t1);
  }
  fps_div_si(t1,sum,-2);
  fps_set(A68051,t1);
  fps_mul_si(t1,A81,2); // t1=2*A81
  fps_mul(t2,A81,A81);  // t2=A81^2
  fps_space(t3,A81,2);  // t3=A81(x^2)
  fps_add(num,t1,t2);
  fps_add(num,num,t3);
  fps_neg(t3,t3);
  fps_setterm_i(t3,1,0); // t3=1-A81(x^2)
  fps_mul_si(t3,t3,4);   // t3=4*(1-A81(x^2))
  fps_div(t1,num,t3);
  fps_add(A68051,A68051,t1);
  fps_clear(t3);
  fps_clear(t2);
  fps_clear(t1);
  fps_clear(sum);
  fps_clear(num);
}

void getA68051(fps_t A68051, fps_t A81) {
  int k,n=fps_len(A81);
  fps_t sum,num,t1,t2,t3;
  sum=fps_init(n);
  fps_zero(sum);
  num=fps_init(n);
  t1=fps_init(n);
  t2=fps_init(n);
  t3=fps_init(n);
  for (k=1; k<=n; k++) {
    fps_log_1mfxk(t2,A81,k);  // t2=log(1-A81(x^k))
    if (0) { // FIXME why doesn't this work?
      fps_mul_q(t1,t2,phi(k),k);// t1=(phi(k)/k)*log(1-A81(x^k))
    } else {
      fps_mul_si(t2,t2,phi(k));
      fps_div_si(t1,t2,k)  ; // t1=(phi(k)/k)*log(1-A81(x^k))
    }
    fps_add(sum,sum,t1);
  }
  fps_div_si(t1,sum,-2);
  fps_set(A68051,t1);
  fps_mul_si(t1,A81,2); // t1=2*A81
  fps_mul(t2,A81,A81);  // t2=A81^2
  fps_space(t3,A81,2);  // t3=A81(x^2)
  fps_add(num,t1,t2);
  fps_add(num,num,t3);
  fps_neg(t3,t3);
  fps_setterm_i(t3,1,0); // t3=1-A81(x^2)
  fps_mul_si(t3,t3,4);   // t3=4*(1-A81(x^2))
  fps_div(t1,num,t3);
  fps_add(A68051,A68051,t1);
  fps_clear(t3);
  fps_clear(t2);
  fps_clear(t1);
  fps_clear(sum);
  fps_clear(num);
}


int main(int argc, char* argv[]) {
  int n=3000;
  fps_t A81,A1429,A27852,A68051;
  if (argc>1) n=atoi(argv[1]); 
  fprintf(stderr,"%s\n",fps_version);
  A81=fps_init(n);
  A1429=fps_init(n);
  A68051=fps_init(n);
  A27852=fps_init(n);
  fps_timing(0);
  getA81(A81,n);
  //readA81(A81,n);
  printf("A81:\n"); fps_timing(1);
  //fps_list(A81);
  getA27852(A27852,A81);
  printf("A27852:\n"); fps_timing(1);
  //fps_list(A27852);
  getA68051(A68051,A81);
  printf("A68051:\n"); fps_timing(1);
  //fps_list(A68051);
  fps_set(A1429,A68051);
  fps_sub(A1429,A1429,A27852);
  fps_sub(A1429,A1429,A81);
  printf("A1429: (unlabelled unicycles)\n");
  fps_list(A1429);
  return 0;
}
