deleted incorrect var numPaulis and replaced with numrandomsteps in test2 bash script
[strong_simulation_stabilizer_rank.git] / strongsim2.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <complex.h>
6 #include "matrix.h"
7 #include "exponentialsum.h"
8 #include "shrink.h"
9 #include "extend.h"
10 #include "measurepauli.h"
11 #include "innerproduct.h"
12
13 int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits);
14
15 // order of matrix elements is [row][column]!!!
16
17 int main()
18 {
19
20   int N;              // number of qubits
21   scanf("%d", &N);
22
23   if(N%2 != 0) {
24     printf("'N' needs to be an even number for a k=2 tensor factor decomposition!\n");
25     return 1;
26   }
27
28   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)
29   scanf("%d", &T);  
30
31   int omega;
32   int alpha[N], beta[N], gamma[N], delta[N];
33   int Paulicounter = 0;
34
35   int i, j, k, l, m;
36
37
38   int n1 = 2; int k1 = 1; int (*(G1[])) = { (int[]) {1, 1}, (int[]) {0, 1} }; int (*(GBar1[])) = { (int[]) {1, 0}, (int[]) {1, 1} }; int h1[] = {0, 0}; int Q1 = 0; int D1[] = {2}; int (*(J1[])) = { (int[]) {4} };
39   int n2 = 2; int k2 = 1; int (*(G2[])) = { (int[]) {1, 1}, (int[]) {0, 1} }; int (*(GBar2[])) = { (int[]) {1, 0}, (int[]) {1, 1} }; int h2[] = {0, 1}; int Q2 = 0; int D2[] = {0}; int (*(J2[])) = { (int[]) {0} };
40
41   int *K; int ***G; int ***GBar; int **h; int *Q; int **D; int ***J;
42   double complex Gamma[(int)pow(2.0,N/2)]; // prefactor in front of resultant state
43   G = calloc(pow(2,N/2),sizeof(int*)); GBar = calloc(pow(2,N/2),sizeof(int*));
44   h = calloc(pow(2,N/2),sizeof(int*));
45   
46   J = calloc(pow(2,N/2),sizeof(int*)); D = calloc(pow(2,N/2),sizeof(int*)); Q = calloc(pow(2,N/2),sizeof(int));
47
48   K = calloc(pow(2,N/2), sizeof(int));
49
50   double complex origGamma[(int)pow(2,N/2)];
51   int *origK, *origQ, **origD, ***origJ;
52   int ***origG, ***origGBar, **origh;
53
54   origG = calloc(pow(2,N/2),sizeof(int*)); origGBar = calloc(pow(2,N/2),sizeof(int*));
55   origh = calloc(pow(2,N/2),sizeof(int*));
56   
57   origJ = calloc(pow(2,N/2),sizeof(int*)); origD = calloc(pow(2,N/2),sizeof(int*)); origQ = calloc(pow(2,N/2),sizeof(int));
58
59   origK = calloc(pow(2,N/2), sizeof(int));
60
61   int combination; // a particular combination from the linear combo of stabilizer states making up the tensor factors multiplied together
62   
63
64   for(j=0; j<pow(2,N/2); j++) { // there will be 2^(N/2) combinations when using k=2 tensor factors
65
66     K[j] = k1*N/2; // assuming k1=k2
67     origK[j] = K[j];
68
69     combination = j;
70
71     Gamma[j] = 1.0;
72     
73     G[j] = calloc(N, sizeof(int*)); GBar[j] = calloc(N, sizeof(int*));
74     h[j] = calloc(N, sizeof(int));
75
76     if(K[j] > 0) {
77       J[j] = calloc(K[j], sizeof(int*)); D[j] = calloc(K[j], sizeof(int));
78       for(k=0; k<K[j]; k++)
79         J[j][k] = calloc(K[j], sizeof(int));
80     }
81
82     origG[j] = calloc(N, sizeof(int*)); origGBar[j] = calloc(N, sizeof(int*));
83     origh[j] = calloc(N, sizeof(int));
84     
85     if(K[j] > 0) {
86       origJ[j] = calloc(K[j], sizeof(int*)); origD[j] = calloc(K[j], sizeof(int));
87       for(k=0; k<K[j]; k++)
88         origJ[j][k] = calloc(K[j], sizeof(int));
89     }
90
91     for(k=0; k<N/2; k++) {
92
93       Q[j] += (combination & 0x1)*Q2 + (~combination & 0x1)*Q1;
94       
95       Gamma[j] *= (1.0/sqrt(2.0))*((combination & 0x1)*cexp(0.25*PI*I) + (~combination & 0x1)*cexp(0.0*PI*I));
96       
97       G[j][k] = calloc(N, sizeof(int)); GBar[j][k] = calloc(N, sizeof(int));
98       G[j][N/2+k] = calloc(N, sizeof(int)); GBar[j][N/2+k] = calloc(N, sizeof(int));
99
100       origG[j][k] = calloc(N, sizeof(int)); origGBar[j][k] = calloc(N, sizeof(int));
101       origG[j][N/2+k] = calloc(N, sizeof(int)); origGBar[j][N/2+k] = calloc(N, sizeof(int));
102       
103       for(l=0; l<k1; l++) { // assuming k1=k2
104         D[j][k*k1+l] = (combination & 0x1)*D2[l] + (~combination & 0x1)*D1[l];
105         for(m=0; m<k1; m++) // assuming k1=k2
106           J[j][k*k1+l][k*k1+m] = (combination & 0x1)*J2[l][m] + (~combination & 0x1)*J1[l][m];
107       }
108             
109       for(l=0; l<n1; l++) { // assuming n1=n2
110         h[j][k*n1+l] = (combination & 0x1)*h2[l] + (~combination & 0x1)*h1[l];
111         G[j][k][k*n1+l] = (combination & 0x1)*G2[0][l] + (~combination & 0x1)*G1[0][l];
112         G[j][N/2+k][k*n1+l] = (combination & 0x1)*G2[1][l] + (~combination & 0x1)*G1[1][l]; // basis outside of support
113         GBar[j][k][k*n1+l] = (combination & 0x1)*GBar2[0][l] + (~combination & 0x1)*GBar1[0][l];
114         GBar[j][N/2+k][k*n1+l] = (combination & 0x1)*GBar2[1][l] + (~combination & 0x1)*GBar1[1][l]; // basis outside of support
115       }
116       memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
117       memcpy(origG[j][N/2+k], G[j][N/2+k], N*sizeof(int)); memcpy(origGBar[j][N/2+k], GBar[j][N/2+k], N*sizeof(int));
118
119       memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));
120       
121       combination /= 2; // shift to the right by one (in base-2 arithmetic)
122     }
123
124     memcpy(origh[j], h[j], N*sizeof(int));
125     memcpy(origD[j], D[j], K[j]*sizeof(int));
126
127   }
128   memcpy(origGamma, Gamma, pow(2,N/2)*sizeof(double complex));
129
130   memcpy(origQ, Q, pow(2,N/2)*sizeof(int));
131
132   while(readPaulicoeffs(&omega, alpha, beta, gamma, delta, N)) {
133
134     Paulicounter++;
135     if(Paulicounter > N) {
136       printf("Error: Number of Paulis is greater than N!\n");
137       return 1;
138     }
139     
140     // Let's break up the Ys into Xs and Zs in the order Z X, as required to pass to measurepauli()
141     // Y_i = -I*Z*X
142     for(i=0; i<N; i++) {
143       if(delta[i]){
144         omega += 3; // -I = I^3
145         beta[i] = delta[i];
146         gamma[i] = delta[i];
147       }
148     }
149
150     for(j=0; j<pow(2,N/2); j++) { // the kets
151
152       Gamma[j] *= measurepauli(N, &K[j], h[j], G[j], GBar[j], &Q[j], &D[j], &J[j], omega, gamma, beta);
153
154     }
155
156   }
157
158   double complex amplitude = 0.0 + 0.0*I;
159   for(i=0; i<pow(2,N/2); i++) { // the bras
160     for(j=0; j<pow(2,N/2); j++) {
161       // check to see if second arguments are modified!!! They shouldn't be!
162       double complex newamplitude = innerproduct(N, K[j], h[j], G[j], GBar[j], Q[j], D[j], J[j], N, origK[i], origh[i], origG[i], origGBar[i], origQ[i], origD[i], origJ[i]);
163       amplitude = amplitude + conj(origGamma[i])*Gamma[j]*newamplitude;
164     }
165   }
166
167   printf("amplitude:\n");
168   if(creal(amplitude+0.00000001)>0)
169     printf("%lf %c %lf I\n", cabs(creal(amplitude)), cimag(amplitude)>0?'+':'-' , cabs(cimag(amplitude)));
170   else
171     printf("%lf %c %lf I\n", creal(amplitude), cimag(amplitude)>0?'+':'-' , cabs(cimag(amplitude)));
172   //printf("%lf %c %lf I\n", creal(amplitude), cimag(amplitude)>0?'+':'-' , cabs(cimag(amplitude)));
173
174   return 0;
175
176 }
177
178
179
180 int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits)
181 {
182     
183   int newomega, newalpha, newbeta, newgamma, newdelta;
184   int i;
185
186   if(scanf("%d", &newomega) != EOF) {
187     *omega = newomega;
188     for(i=0; i<numqubits; i++) {
189       if(scanf("%d %d %d %d", &newalpha, &newbeta, &newgamma, &newdelta) == EOF) {
190         printf("Error: Too few input coeffs!\n");
191         exit(0);
192       }
193       if(newalpha+newbeta+newgamma+newdelta > 1) {
194         printf("Error: Too many coefficients are non-zero at Pauli %d!\n", i);
195         exit(0);
196       }
197       alpha[i] = newalpha; beta[i] = newbeta; gamma[i] = newgamma; delta[i] = newdelta;
198     }
199     return 1;
200   } else
201     return 0;
202     
203 }
204
205
206
207
208
209
210