final v1.0 files
[weak_simulation_stab_extent.git] / weaksim_relerr.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <complex.h>
6 #include <time.h>
7 #include "matrix.h"
8 #include "exponentialsum.h"
9 #include "shrinkstar.h"
10 #include "extend.h"
11 #include "measurepauli.h"
12 #include "innerproduct.h"
13 #include "randomstabilizerstate.h"
14 #include "sparsify.h"
15
16 #define ZEROTHRESHOLD (0.00000001)
17
18 int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits);
19
20 // order of matrix elements is [row][column]!!!
21
22 int main(int argc, char *argv[])
23 {
24
25   if(argc != 5) {
26     printf("weaksim_rellerr argument: \"number of stabilizer state samples\" \"additive error delta\" \"phi (times PI)\" \"coherent sampling (0=no; 1=yes)\"\n");
27     exit(0);
28   }
29
30   int NUMSTABSTATESAMPLES = atoi(argv[1]);        // number of stabilizer state samples
31   double additiveErrorDelta = atof(argv[2]);        // additive error delta
32   double phi = PI*atof(argv[3]);//PI/4.0; // PI/4.0 is the T gate magic state
33   int coherentSampling = atoi(argv[4]);           // perform coherent sampling (true=1 or false=0)
34
35   int N;                  // number of qubits
36   scanf("%d", &N);
37
38   int T;              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
39   scanf("%d", &T);
40
41   printf("phi = %lf\n", phi);
42
43   int omega[N]; // max of N measurements
44   int alpha[N][N], beta[N][N], gamma[N][N], delta[N][N]; // max of N measurements of N Paulis
45   int Paulicounter = 0;
46
47   int i, j, k, l, m;
48
49   FILE *fp;
50   char buff[255];
51
52   srand((unsigned)time(NULL)); // seeding the random number generator for randomstabilizerstate()
53   
54   fp = fopen("Pd.txt", "r");
55
56   if(fscanf(fp, "%s", buff) == EOF) {
57     printf("Error: Pd.txt should start with the number N of P(d) of values tabulated.");
58     return 1;
59   }
60   
61   double** Pd;
62
63   int PdN = atoi(buff);
64
65   Pd = calloc(PdN, sizeof(double*));
66   for(i=0; i<PdN; i++) 
67     Pd[i] = calloc(PdN+1, sizeof(double));
68
69   double tmp;
70   
71   for(i=1; i<PdN; i++) {
72     tmp = 0.0;
73     for(j=0; j<=i; j++) {
74       if(fscanf(fp, "%s", buff) == EOF) {
75         printf("Error: expected more values tabulated for P(d) for N=%d", PdN);
76         return 1;
77       }
78       Pd[i][j] = atof(buff);
79       //printf("%e ", Pd[i][j]);
80       tmp += Pd[i][j];
81     }
82     //printf("\n");
83     //printf("total=%f\n", tmp);
84   }
85
86   double complex amplitude;
87   
88   double complex coeffa = cexp(I*carg(cexp(PI*I/8.0)*0.5*csqrt(4.0-2.0*csqrt(2.0))*cexp(-PI*I*0.25)*I/sqrt(2.0)*(-I+cexp(-0.25*PI*I))*(-I+cexp(I*phi)))); // factor of cexp(PI*I/8.0)*cexp(-PI*I*0.25) comes from converting (|0>+|1>)/sqrt(2) under e^(pi*i/8) H S^\dagger to take it from |H> to |T>
89   double complex coeffb = cexp(I*carg(cexp(PI*I/8.0)*0.5*csqrt(4.0-2.0*csqrt(2.0))*I/sqrt(2.0)*(1.0+cexp(-0.25*PI*I))*(1.0-cexp(I*phi)))); // factor of cexp(PI*I/8.0) comes from converting |0> under e^(pi*i/8) H S^\dagger to take it from |H> to |T>
90   // alternative coefficient to use instead of coeffb to get overall entangled state
91   double complex coeffbb = cexp(I*carg(cexp(PI*I/8.0)*0.5*csqrt(4.0-2.0*csqrt(2.0))*I/sqrt(2.0)*(1.0+cexp(-0.25*PI*I))*(1.0-cexp(I*0.25*PI))));
92
93   int n1 = 1; int k1 = 1; int (*(G1[])) = { (int[]) {1} }; int (*(GBar1[])) = { (int[]) {1} }; int h1[] = {0}; int Q1 = 0; int D1[] = {2}; int (*(J1[])) = { (int[]) {4} };
94   int n2 = 1; int k2 = 1; int (*(G2[])) = { (int[]) {1} }; int (*(GBar2[])) = { (int[]) {1} }; int h2[] = {0}; int Q2 = 0; int D2[] = {0}; int (*(J2[])) = { (int[]) {0} };
95
96   long* stabStateIndices;
97   int numStabStates;
98
99   srand((unsigned)time(NULL)); // seeding the random number generator for sparsify()
100
101
102   if(sparsify(&stabStateIndices, &numStabStates, T, phi, additiveErrorDelta, coherentSampling))
103     return 1;
104
105   //printf("checking: numStabStateIndices:\n");
106   //for(i=0; i<numStabStates; i++)
107   //  printf("%ld ", stabStateIndices[i]);
108   //printf("\n");
109   //fflush(stdout);
110
111   int *K; int ***G; int ***GBar; int **h; int *Q; int **D; int ***J;
112   double complex Gamma[(int)numStabStates]; // prefactor in front of resultant state
113   G = calloc(numStabStates,sizeof(int*)); GBar = calloc(numStabStates,sizeof(int*));
114   h = calloc(numStabStates,sizeof(int*));
115   
116   J = calloc(numStabStates,sizeof(int*)); D = calloc(numStabStates,sizeof(int*)); Q = calloc(numStabStates,sizeof(int));
117
118   K = calloc(numStabStates, sizeof(int));
119
120   int origK, origQ, *origD;
121   int **origJ;
122   int **origG, **origGBar;
123   int *origh;
124   double complex origGamma;
125
126   long combination; // a particular combination from the linear combo of stabilizer states making up the tensor factors multiplied together
127   
128   double L1Norm = pow(sqrt(1-sin(phi)) + sqrt(1-cos(phi)),T);
129
130   for(j=0; j<numStabStates; j++) {
131
132     combination = stabStateIndices[j];
133
134     K[j] = 0.0;
135     
136     for(k=0; k<N; k++) {
137       K[j] += (((combination%2)==1)*k2 + ((combination%2)==0)*k1);
138       combination /= 2;
139     }
140     combination = j;
141
142     Gamma[j] = 1.0;
143     Gamma[j] *= L1Norm/((double)numStabStates);
144
145     // the coefficients which are a product of 'coeffa', 'coeffb', 'coeffbb' (that are subsequently multiplied into Gamma[j]) is multiplied by 'norm'
146     //Gamma[j] *= norm;
147
148     G[j] = calloc(N, sizeof(int*)); GBar[j] = calloc(N, sizeof(int*));
149     h[j] = calloc(N, sizeof(int));
150
151     if(K[j] > 0) {
152       J[j] = calloc(K[j], sizeof(int*)); D[j] = calloc(K[j], sizeof(int));
153       for(k=0; k<K[j]; k++)
154         J[j][k] = calloc(K[j], sizeof(int));
155     }
156
157     for(k=0; k<N; k++) {
158       G[j][k] = calloc(N, sizeof(int)); GBar[j][k] = calloc(N, sizeof(int));
159     }
160
161     int Kcounter = 0; // Kcounter keeps track of the K<=N that we have added already to the G rows etc. for each combination that is indexed by the digits (base 3) of 'j' in that we go through with 'k'
162     int Kcombo; // Kcombo stores the k<(n1=n2=n3) dimension of the member of the combination that we are currently adding
163
164     // if combination contains at least one instance of the second state, i.e. contains the 0 digit in binary, then we want to have it have one instance of coeffb instead of coeffbb
165     for(k=0; k<N; k++) {
166       if(combination%2==1) {
167         Gamma[j] *= coeffb/coeffbb;
168         break; // break out of loop
169       }
170       combination /= 2; // shift to the right by one (in base-2 arithmetic)
171     }
172     combination = stabStateIndices[j];
173
174     for(k=0; k<N; k++) {
175
176       Q[j] += (((combination%2)==1)*Q2 + ((combination%2)==0)*Q1);
177       
178
179       Gamma[j] *= (((combination%2)==1)*coeffbb + ((combination%2)==0)*coeffa); // only assign coeffbb instead of coeffb; coeffb replaces one instance of coeffbb before this loop
180
181       Kcombo = (((combination%2)==1)*k2 + ((combination%2)==0)*k1);
182       for(l=0; l<Kcombo; l++) {
183         // D1 has a different number of rows 'l' than D2 so you need to use something like 'switch' to check combination%2 without going out of bound of J1
184         switch(combination%2) {
185         case 0:
186           D[j][Kcounter+l] = D1[l];
187           break;
188         case 1:
189           D[j][Kcounter+l] = D2[l];
190           break;
191         default:
192           printf("error");
193           return 1;
194           }
195         for(m=0; m<Kcombo; m++) {
196           // J1 has a different number of rows 'l' than J2 so you need to use something like 'switch' to check combination%2 without going out of bound of J1
197           switch(combination%2) {
198           case 0:
199             J[j][Kcounter+l][Kcounter+m] = J1[l][m];
200             break;
201           case 1:
202             J[j][Kcounter+l][Kcounter+m] = J2[l][m];
203             break;
204           default:
205             printf("error");
206             return 1;
207           }
208         }
209       }
210
211       for(l=0; l<n1; l++) { // assuming n1=n2
212         h[j][k*n1+l] = (((combination%2)==1)*h2[l] + ((combination%2)==0)*h1[l]);
213       }
214       // only filling the K[j] first rows of G and GBar here corresponding to the basis for D and J
215       for(l=0; l<Kcombo; l++) {
216         for(m=0; m<n1; m++) { // assuming n1=n2
217           G[j][Kcounter+l][k*n1+m] = (((combination%2)==1)*G2[l][m] + ((combination%2)==0)*G1[l][m]);
218           GBar[j][Kcounter+l][k*n1+m] = (((combination%2)==1)*GBar2[l][m] + ((combination%2)==0)*GBar1[l][m]);
219         }
220       }
221       Kcounter = Kcounter + Kcombo;
222       
223       /* printf("intermediate G[%d]:\n", j); */
224       /* printMatrix(G[j], N, N); */
225       /* printf("intermediate GBar[%d]:\n", j); */
226       /* printMatrix(GBar[j], N, N); */
227       //memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
228
229       //memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));
230       
231       combination /= 2; // shift to the right by one (in base-7 arithmetic)
232     }
233     //printf("!\n");
234
235     // now need to fill the N-Kcounter remaining rows of G and GBar that are outside the spanning basis states of D and J
236     combination = j;
237     for(k=0; k<(N); k++) {
238       Kcombo = (((combination%2)==1)*k2 + ((combination%2)==0)*k1);
239       //printf("Kcounter=%d\n", Kcounter);
240       // G and GBar rows that are outside the first 'k' spanning basis states
241       for(l=Kcombo; l<n1; l++) { // assuming n1=n2=n3
242         //printf("l=%d\n", l);
243         for(m=0; m<n1; m++) { // assuming n1=n2=n3
244           /* printf("m=%d\n", m); */
245           /* printf("Kcounter+l=%d\n", Kcounter+l); */
246           /* printf("k*n1+m=%d\n", k*n1+m); */
247           G[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%2)==1)*G2[l][m] + ((combination%2)==0)*G1[l][m]);
248           GBar[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%2)==1)*GBar2[l][m] + ((combination%2)==0)*GBar1[l][m]);
249         }
250       }
251       Kcounter = Kcounter + (n1-Kcombo);
252
253       /* printf("intermediate G[%d]:\n", j); */
254       /* printMatrix(G[j], N, N); */
255       /* printf("intermediate GBar[%d]:\n", j); */
256       /* printMatrix(GBar[j], N, N); */
257       
258       combination /= 2;
259     }
260
261     /*printf("G[%d]:\n", j);
262     printMatrix(G[j], N, N);
263     printf("GBar[%d]:\n", j);
264     printMatrix(GBar[j], N, N);
265
266     printf("h[%d]:\n", j);
267     printVector(h[j], N);
268
269     printf("J[%d]:\n", j);
270     printMatrix(J[j], K[j], K[j]);
271     
272     printf("D[%d]:\n", j);
273     printVector(D[j], K[j]);
274
275     printf("Q[%d]=%d\n", j, Q[j]);*/
276
277   }
278   //exit(0);
279
280   while(readPaulicoeffs(&omega[Paulicounter], alpha[Paulicounter], beta[Paulicounter], gamma[Paulicounter], delta[Paulicounter], N)) {
281
282     if((Paulicounter+1) > N) {
283       printf("Error: Number of Paulis is greater than N!\n");
284       return 1;
285     }
286     
287     // Let's break up the Ys into Xs and Zs in the order Z X, as required to pass to measurepauli()
288     // Y_i = -I*Z*X
289     for(i=0; i<N; i++) {
290       if(delta[Paulicounter][i]){
291         omega[Paulicounter] += 3; // -I = I^3
292         beta[Paulicounter][i] = delta[Paulicounter][i];
293         gamma[Paulicounter][i] = delta[Paulicounter][i];
294       }
295     }
296
297     /*printf("*******\n");
298     printf("*******\n");
299     printf("omega=%d\n", omega);
300     printf("X:\n");
301     printVector(gamma, N);
302     printf("Z:\n");
303     printVector(beta, N);
304     printf("*******\n");
305     printf("*******\n");*/
306
307     //for(j=0; j<numStabStates; j++) { // the kets
308
309       /*printf("========\n");
310       printf("before:\n");
311       printf("K=%d\n", K[j]);
312       printf("h:\n");
313       printVector(h[j], N);
314       printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
315       printf("G:\n");
316       printMatrix(G[j], N, N);
317       printf("GBar:\n");
318       printMatrix(GBar[j], N, N);
319       printf("Q=%d\n", Q[j]);
320       printf("D:\n");
321       printVector(D[j], K[j]);
322       printf("J:\n");
323       printMatrix(J[j], K[j], K[j]);*/
324       //Gamma[j] *= measurepauli(N, &K[j], h[j], G[j], GBar[j], &Q[j], &D[j], &J[j], omega, gamma, beta);
325       /*printf("\nafter:\n");
326       printf("K=%d\n", K[j]);
327       printf("h:\n");
328       printVector(h[j], N);
329       printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
330       printf("G:\n");
331       printMatrix(G[j], N, N);
332       printf("GBar:\n");
333       printMatrix(GBar[j], N, N);
334       printf("Q=%d\n", Q[j]);
335       printf("D:\n");
336       printVector(D[j], K[j]);
337       printf("J:\n");
338       printMatrix(J[j], K[j], K[j]);*/
339
340     //}
341
342     Paulicounter++;
343   }
344
345   amplitude = 0.0 + 0.0*I;
346   for(i=0; i<NUMSTABSTATESAMPLES; i++) { // the bras
347     //printf("i=%d\n", i);
348
349     randomstabilizerstate(N, &origK, &origh, &origG, &origGBar, &origQ, &origD, &origJ, Pd);
350
351     origGamma = 1.0 + 0.0*I;
352     
353     for(k=0; k<Paulicounter; k++) {
354       origGamma *= measurepauli(N, &origK, origh, origG, origGBar, &origQ, &origD, &origJ, omega[k], gamma[k], beta[k]);
355       //printf("k=%d\n", k);
356   }
357     /*printf("origK=%d\n", origK);
358     printf("origG:\n");
359     printMatrix(origG, N, N);
360     printf("origGBar:\n");
361     printMatrix(origGBar, N, N);
362     printf("origh:\n");
363     printVector(origh, N);*/
364
365     double complex stabstateaverage = 0.0 + 0.0*I;
366     
367     for(j=0; j<numStabStates; j++) {
368       //printf("j=%d\n", j);
369       double complex newamplitude = innerproduct(N, K[j], h[j], G[j], GBar[j], Q[j], D[j], J[j], N, origK, origh, origG, origGBar, origQ, origD, origJ);
370       stabstateaverage = stabstateaverage + origGamma*Gamma[j]*newamplitude;
371     }
372     amplitude = amplitude + conj(stabstateaverage)*stabstateaverage/((double)(NUMSTABSTATESAMPLES))*pow(2.0,T);
373
374     deallocate_mem(&origG, N);
375     deallocate_mem(&origGBar, N);
376     free(origh);
377     deallocate_mem(&origJ, origK);
378     free(origD);
379   }
380
381   //printf("numStabStates=%d\n", numStabStates);
382   printf("L1Norm=%lf\n", L1Norm);
383
384   printf("\namplitude:\n");
385   if(creal(amplitude+ZEROTHRESHOLD)>0)
386     printf("%.10lf %c %.10lf I\n", cabs(creal(amplitude)), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
387   else
388     printf("%.10lf %c %.10lf I\n", creal(amplitude), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
389   printf("\nabs(amplitude):\n");
390   printf("%lf\n", cabs(amplitude));
391
392
393   for(i=0; i<PdN; i++) 
394     free(Pd[i]);
395   free(Pd);
396
397   return 0;
398 }
399
400 int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits)
401 {
402     
403   int newomega, newalpha, newbeta, newgamma, newdelta;
404   int i;
405
406   if(scanf("%d", &newomega) != EOF) {
407     *omega = newomega;
408     for(i=0; i<numqubits; i++) {
409       if(scanf("%d %d %d %d", &newalpha, &newbeta, &newgamma, &newdelta) == EOF) {
410         printf("Error: Too few input coeffs!\n");
411         exit(0);
412       }
413       if(newalpha+newbeta+newgamma+newdelta > 1) {
414         printf("Error: Too many coefficients are non-zero at Pauli %d!\n", i);
415         exit(0);
416       }
417       alpha[i] = newalpha; beta[i] = newbeta; gamma[i] = newgamma; delta[i] = newdelta;
418     }
419     return 1;
420   } else
421     return 0;
422     
423 }