/*CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C                                                                             C
C  COMPUTE DIRICHLET PRODUCTS AND MOBIUS INVERSES			      C
C  05/20/19 (DKC)							      C
C									      C
C  Set "mobinv" to 1, "check" to 0, "outind" to 0" to do Mobius inverse.      C
C  If extracting a sub-curve, set "extra" to 1 and "p" and "subcur" to        C
C  appropriate values.	Set appropriate "norm" and "factor" values ("factor"  C
C  depends on "MAXN").                                                        C
C                                                                             C
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC*/
#include <stdio.h>
#include <math.h>
#include "table2.h" // prime look-up table
//#include "gue45.h"  // Gaussian ensemble (4500x4500 matrix)
#include "zero1.h"         // 100000 zeros (more precision)
//#include "rand.h"       // 2001 uniformly distributed values
extern char *malloc();
unsigned int nucheck(unsigned int N, unsigned int p, unsigned int pprod,
  unsigned int subcur, unsigned int size, unsigned int *table,
  unsigned int *skip, unsigned int nope);
double interp1(double ND, double ND1, unsigned int I,
	       double init, double *out);
unsigned int primed(unsigned int *out, unsigned int tsize,
		    unsigned int *table,unsigned int limit);
int mobius(unsigned int a, unsigned int *table1, unsigned int t1size);
//
unsigned int gue=0;  // if set, use Gaussian ensemble
unsigned int MAXN=64;
unsigned int I=2;  // number of values to interpolate
unsigned int numlim=32;
unsigned int scale=0;  // if set to 1, take logarithms of zeros                       // if set to 2, take logarithms of zeros
unsigned int nonorm=1;	// if (set, don't normalize
unsigned int check=0; // check if N is prime, etc.
unsigned int p=3;   // power of prime (up to 17 complete)
unsigned int pprod=1; // if set when p>1 and odd, do primes and combinations
unsigned int subcur=2;	// sub-curves, set to 0 to do all
unsigned int nope=0;  // if set when p=3, omit primes even if skip[3]==0
unsigned int outind=0;	// if set, output indices too
unsigned int mobinv=1;  // if set, do Mobius inversion
unsigned int comp=2;  // if set to 1, take differences
		      // if set to 2, compute relative error
unsigned int clip=1;  // if set only output upper half (comp=2 only)
unsigned int extra=0;  // if set, extract sub-curve (comp=0 only)
double norm=31.713108; // I=2 (extra=0 only)
//double norm=80.453014;  // I=2, n=pq (3.2)
//double norm=250.147742;  // I=2, n=pqr (7.3)
//double norm=1101.339335;  // I=5, p^3q^2r (17.3)
//double norm=298.432389;  // I=2, n=p^2q^2 (9.3)
//double norm=1061.644516;  // I=2, n=p^3q^3 (13.6)
//double norm=-1505.145075;  // I=4, n=pqr (eigenvalues)
//double norm=-754.461338;  // I=2, n=pq (eigenvalues)
//
double factor=1.66103262;  // 64 I=2
//double factor=1.71146907;  // 128
//double factor=1.73182393;  // 256
//double factor=1.78701587;  // 512
//double factor=1.78691539;  // 1024
//double factor=1.80503140;  // 2048
//double factor=1.82016313;  // 4096
//double factor=1.82643984;  // 8192
//double factor=1.84477360;  // 16384
//double factor=1.85090537;  // 32768
//double factor=1.86106885;  // 65536
//double factor=1.87007977;  // 131072
//double factor=1.87746605;  // 262144
//double factor=1.88544670;  // 524288
//double factor=1.89075898;  // 1048576
//double factor=1.89658165;  // 2097152
//double factor=1.90156268;  // 4194304
//
//double factor=1.69176559; // 128 I=2, n=pq
//double factor=1.71556600; // 256
//double factor=1.73199042; // 512
//double factor=1.78817824; // 1024
//double factor=1.78893021; // 2048
//double factor=1.80629720; // 4096
//double factor=1.82068655; // 8192
//double factor=1.82661960; // 16384
//double factor=1.84565112; // 32768
//double factor=1.85122113; // 65536
//double factor=1.86125581; // 131072
//double factor=1.87018543; // 262144
//double factor=1.87739527; // 524288
//double factor=1.88581843; // 1048576
//double factor=1.89089448; // 2097152
//double factor=1.8970613867;  // 4194304
//
//double factor=1.57416755;   // 256 I=2, n=pqr
//double factor= 1.78315930;  // 512
//double factor= 1.72542247;  // 1024
//double factor= 1.74374660;  // 2048
//double factor= 1.79300287;  // 4096
//double factor= 1.78852346;  // 8192
//double factor= 1.81300810;  // 16348
//double factor= 1.82412852;  // 32768
//double factor= 1.84018826;  // 65536
//double factor= 1.84683077;  // 131072
//double factor= 1.85996662;  // 262144
//double factor= 1.86524311;  // 524288
//double factor= 1.87329003;  // 1048576
//double factor=1.8824472896; // 2097152
//double factor=1.8875485468; // 4194304
//
//double factor=3.6791295316;  // 20000 I=5 n=p^3q^2r
//double factor=3.8493129276;  // 100000
//double factor=4.03015276;    // 500000
//double factor=4.17672296;    // 2500000
//
//double factor=1.82575404;  // 8192 n=p^2q^2
//double factor=1.81291183;  // 16384
//double factor=1.81871522;  // 32768
//double factor=1.67551833;  // 65536
//double factor=1.75388948;  // 131072
//double factor=1.82191754;  // 262144
//double factor=1.80401095;  // 524288
//double factor=1.87108078;  // 1048576
//double factor=1.81071449;  // 2097152
//double factor=1.8255899111;  // 4194304
//
//double factor=1.64990162;  // 262144, n=p^3q^3
//double factor=1.65460131;  // 524288
//double factor=2.30200446;  // 1048576
//double factor=1.63679995;  // 2097152
//double factor=1.9350651633; // 4194304
//
//double factor=2.5989836788;  // 1000, n=pqr (eigenvalues)
//double factor=1.61998712996;  // 1000, n=pq (eigenvalues)

	    // 0, 1, 2, 3, 4 for p=3 (includes p^2 and p)
	    // 0, 1, 2, 3 for p=5 (includes p^4)
	    // 0, 1, 2, 3, 4 for p=7 (includes p^6)
	    // 0, 1, 2, 3, 4 for p=9 (includes p^8 [use])
	    // 0, 1, 2, 3, 4, 5 for p=11 (includes p^10)
	    // 0, 1, 2, 3, 4, 5, 6, 7, 8 for p=13 (includes p^12)
	    // 0, 1, 2, 3, 4, 5, 6, 7, 8 for p=15 (includes p^14)
	    // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 for p=17 (includes p^16)
            // 0, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 for p=19 (also p^18)
            // 0,1,2,3,4,5,6,7,8,9,10,11,12 for p=21 (includes p^20)
// 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22 for p=23
// 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27 for p=25
// 0,1,2,3, ..., 35 for p=27
//
// make sure to check skip[19], should be zero for p=3 only (for bypass)
//
//unsigned int skip[20]={1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};  // p=8
//unsigned int skip[20]={0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; // p=9
//unsigned int skip[20]={1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1}; // p=13
//unsigned int skip[20]={1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1}; // p=15
//unsigned int skip[20]={1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; // p=15
//unsigned int skip[20]={1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1}; // p=17
//unsigned int skip[20]={1,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,0,1,1,1}; // p=19
//unsigned int skip[20]={1,1,1,1,1,1,0,1,1,1,1,1,0,0,1,0,1,1,1,1}; // p=19
//unsigned int skip[20]={1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; // p=19
//unsigned int skip[20]={1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1}; // p=19
//unsigned int skip[20]={1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1};  // p=19
//unsigned int skip[20]={1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1};   // p=19
//unsigned int skip[20]={0,1,0,1,1,1,0,1,0,1,1,0,0,0,0,0,0,0,0,1}; // p=21
//unsigned int skip[20]={1,0,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,1};  // p=21
//unsigned int skip[20]={1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1};
//unsigned int skip[27]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; // p=23
//unsigned int skip[27]={1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1};
//unsigned int skip[27]={1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0}; // #25d
//unsigned int skip[27]={1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1}; // #25e
unsigned int skip[35]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
//
unsigned int rnd=0;	// if set, scale up the standard uniform distribution
double rndfact=5600.0;   // factor
unsigned int tsize=17984;  // prime look-up table size
//
void main() {
unsigned int i,N,count,t1size;
unsigned int *table1;
double *output,*dout;
double init,sum,max;
double min,temp;
FILE *Outfp;
Outfp = fopen("out2.dat","w");
if ((check!=0)&&(extra!=0)) {
   printf("check and extra both set \n");
   return;
   }
output=(double*) malloc(800008);
if (output==NULL) {
   printf("not enough memory \n");
   return;
   }
dout=(double*) malloc(800008);
if (dout==NULL) {
   printf("not enough memory \n");
   return;
   }
if (output==NULL) {
   printf("not enough memory \n");
   return;
   }
table1=(unsigned int*) malloc(800008);
if (table1==NULL) {
   printf("not enough memory \n");
   return;
   }
t1size=primed(table1,tsize,table,100000); // make larger prime look-up table
printf("prime look-up table size=%d, last prime=%d \n",t1size,table1[t1size-1]);
if (rnd!=0) {
   for (i=0; i<MAXN; i++)
      riem[i]=riem[i]*rndfact;
   }
if (scale==1) {
   for (i=0; i<MAXN; i++)
      riem[i]=log(riem[i]);
   }
init=riem[0];
for (i=0; i<(numlim+1); i++)
   init=interp1(riem[i],riem[i+1],I,init,&output[i*I]);
//
count=0;
min=10000000;
max=0.0;
for (N=1; N<=MAXN; N++) {
   sum=0.0;
   for (i=1; i<=N; i++) {
     if (N==(N/i)*i)
       sum=sum+output[N/i-1];
     }
   if (check!=0) {
     if (nucheck(N,p,pprod,subcur,t1size,table1,skip,nope)==1) {
       count=count+1;
       if (nonorm!=0)
	  temp=sum;
       else
	  temp=sum-output[0];
       printf("N=%d %llf \n",N,temp);
       if (temp>max)
	  max=temp;
       if (temp<min)
	  min=temp;
       if (outind==0)
	  fprintf(Outfp," %llf, \n",temp);
       else
	  fprintf(Outfp," %llf, %d, \n",temp,N);
       }
     }
   else {
      if (N==(N/1000)*1000)
	 printf("N=%d %llf \n",N,sum);
      if (mobinv==0)
	 fprintf(Outfp," %llf, \n",sum);
      else
	dout[N-1]=sum;
     }
   }
if (check!=0)
  printf("count=%d, max=%llf, min=%llf \n",count,max,min);
if ((mobinv==0)||(check!=0))
   goto zskip;
//
// Mobius inversion
//
printf("Mobius inversion \n");
//
// scale
//
if (gue==0)
   dout[0]=14.13472514173470;
else
   dout[0]=-189.1347051;  // eigenvalue
for (i=1; i<MAXN; i++)
   dout[i]=(dout[i]-norm)*factor+norm;
for (N=1; N<=MAXN; N++) {  
   sum=0.0;
   for (i=1; i<=N; i++) {
      if (N==(N/i)*i)
	 sum=sum+dout[i-1]*mobius(N/i,table1,t1size);
      }
   if (N==(N/1000)*1000)
      printf("N=%d %llf \n",N,sum);
   if (comp==0) {
      if (extra==0)
	 fprintf(Outfp," %llf, \n",sum);
      else
	 output[N-1]=sum;
      }
   else {
      if (comp==1)
	fprintf(Outfp," %llf, \n",sum-riem[N-1]);
      else {
	if (clip==0)
	  fprintf(Outfp," %llf, \n",sum/riem[N-1]-1.0);
	else {
	  if (N>(MAXN/I))
	    fprintf(Outfp," %llf, \n",sum/riem[N-1]-1.0);
	  }
	}
      }
   }
if ((extra!=0)&&(comp==0)) {
   count=0;
   for (N=1; N<=MAXN; N++) {
      if (nucheck(N,p,pprod,subcur,t1size,table1,skip,nope)==1) {
	 count=count+1;
	  fprintf(Outfp," %llf, \n",output[N-1]);
	  }
      }
   printf("count=%d \n",count);
   }
zskip:
fclose(Outfp);
return;
}