Distributed QUEST for GPU
QuEST.cpp
Go to the documentation of this file.
1 // Distributed under MIT licence. See https://github.com/aniabrown/QuEST_GPU/blob/master/LICENCE.txt for details
2 
7 # include <math.h>
8 # include <stdio.h>
9 # include <stdlib.h>
10 # include <assert.h>
11 # include "QuEST_precision.h"
12 # include "QuEST.h"
13 # include "QuEST_internal.h"
14 
15 # include "mt19937ar.h" // MT random number generation for random measurement seeding
16 # include <sys/param.h>
17 # include <unistd.h>
18 
19 # include <sys/types.h> // include getpid
20 # include <sys/time.h>
21 
22 # define DEBUG 0
23 
24 const char* errorCodes[] = {
25  "Success", // 0
26  "Invalid target qubit. Note qubits are zero indexed.", // 1
27  "Invalid control qubit. Note qubits are zero indexed.", // 2
28  "Control qubit cannot equal target qubit.", // 3
29  "Invalid number of control qubits", // 4
30  "Invalid unitary matrix.", // 5
31  "Invalid rotation arguments.", // 6
32  "Invalid system size. Cannot print output for systems greater than 5 qubits.", // 7
33  "Can't collapse to state with zero probability.", // 8
34  "Invalid number of qubits.", // 9
35  "Invalid measurement outcome -- must be either 0 or 1." // 10
36 };
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
62 void reportState(MultiQubit multiQubit){
63  FILE *state;
64  char filename[100];
65  long long int index;
66  sprintf(filename, "state_rank_%d.csv", multiQubit.chunkId);
67  state = fopen(filename, "w");
68  if (multiQubit.chunkId==0) fprintf(state, "real, imag\n");
69 
70  for(index=0; index<multiQubit.numAmps; index++){
71  fprintf(state, "%.12f, %.12f\n", multiQubit.stateVec.real[index], multiQubit.stateVec.imag[index]);
72  }
73  fclose(state);
74 }
75 
81  long long int numAmps = 1L << multiQubit.numQubits;
82  long long int numAmpsPerRank = numAmps/multiQubit.numChunks;
83  if (multiQubit.chunkId==0){
84  printf("QUBITS:\n");
85  printf("Number of qubits is %d.\n", multiQubit.numQubits);
86  printf("Number of amps is %lld.\n", numAmps);
87  printf("Number of amps per rank is %lld.\n", numAmpsPerRank);
88  }
89 }
90 
91 void rotateAroundAxis(MultiQubit multiQubit, const int rotQubit, REAL angle, Vector axis){
92 
93  double mag = sqrt(pow(axis.x,2) + pow(axis.y,2) + pow(axis.z,2));
94  Vector unitAxis = {axis.x/mag, axis.y/mag, axis.z/mag};
95 
96  Complex alpha, beta;
97  alpha.real = cos(angle/2.0);
98  alpha.imag = -sin(angle/2.0)*unitAxis.z;
99  beta.real = sin(angle/2.0)*unitAxis.y;
100  beta.imag = -sin(angle/2.0)*unitAxis.x;
101  compactUnitary(multiQubit, rotQubit, alpha, beta);
102 }
103 
104 void rotateX(MultiQubit multiQubit, const int rotQubit, REAL angle){
105 
106  Vector unitAxis = {1, 0, 0};
107  rotateAroundAxis(multiQubit, rotQubit, angle, unitAxis);
108 }
109 
110 void rotateY(MultiQubit multiQubit, const int rotQubit, REAL angle){
111 
112  Vector unitAxis = {0, 1, 0};
113  rotateAroundAxis(multiQubit, rotQubit, angle, unitAxis);
114 }
115 
116 void rotateZ(MultiQubit multiQubit, const int rotQubit, REAL angle){
117 
118  Vector unitAxis = {0, 0, 1};
119  rotateAroundAxis(multiQubit, rotQubit, angle, unitAxis);
120 }
121 
122 void controlledRotateAroundAxis(MultiQubit multiQubit, const int controlQubit, const int targetQubit, REAL angle, Vector axis){
123 
124  double mag = sqrt(pow(axis.x,2) + pow(axis.y,2) + pow(axis.z,2));
125  Vector unitAxis = {axis.x/mag, axis.y/mag, axis.z/mag};
126 
127  Complex alpha, beta;
128  alpha.real = cos(angle/2.0);
129  alpha.imag = -sin(angle/2.0)*unitAxis.z;
130  beta.real = sin(angle/2.0)*unitAxis.y;
131  beta.imag = -sin(angle/2.0)*unitAxis.x;
132  controlledCompactUnitary(multiQubit, controlQubit, targetQubit, alpha, beta);
133 }
134 
135 void controlledRotateX(MultiQubit multiQubit, const int controlQubit, const int targetQubit, REAL angle){
136 
137  Vector unitAxis = {1, 0, 0};
138  controlledRotateAroundAxis(multiQubit, controlQubit, targetQubit, angle, unitAxis);
139 }
140 
141 void controlledRotateY(MultiQubit multiQubit, const int controlQubit, const int targetQubit, REAL angle){
142 
143  Vector unitAxis = {0, 1, 0};
144  controlledRotateAroundAxis(multiQubit, controlQubit, targetQubit, angle, unitAxis);
145 }
146 
147 void controlledRotateZ(MultiQubit multiQubit, const int controlQubit, const int targetQubit, REAL angle){
148 
149  Vector unitAxis = {0, 0, 1};
150  controlledRotateAroundAxis(multiQubit, controlQubit, targetQubit, angle, unitAxis);
151 }
152 
153 void sigmaZ(MultiQubit multiQubit, const int targetQubit)
154 {
155  phaseGate(multiQubit, targetQubit, SIGMA_Z);
156 }
157 
158 void sGate(MultiQubit multiQubit, const int targetQubit)
159 {
160  phaseGate(multiQubit, targetQubit, S_GATE);
161 }
162 
163 void tGate(MultiQubit multiQubit, const int targetQubit)
164 {
165  phaseGate(multiQubit, targetQubit, T_GATE);
166 }
167 
169 
170  if ( fabs(u.r0c0.real*u.r0c0.real
171  + u.r0c0.imag*u.r0c0.imag
172  + u.r1c0.real*u.r1c0.real
173  + u.r1c0.imag*u.r1c0.imag - 1) > REAL_EPS ) return 0;
174  // check
175  if ( fabs(u.r0c1.real*u.r0c1.real
176  + u.r0c1.imag*u.r0c1.imag
177  + u.r1c1.real*u.r1c1.real
178  + u.r1c1.imag*u.r1c1.imag - 1) > REAL_EPS ) return 0;
179 
180  if ( fabs(u.r0c0.real*u.r0c1.real
181  + u.r0c0.imag*u.r0c1.imag
182  + u.r1c0.real*u.r1c1.real
183  + u.r1c0.imag*u.r1c1.imag) > REAL_EPS ) return 0;
184 
185  if ( fabs(u.r0c1.real*u.r0c0.imag
186  - u.r0c0.real*u.r0c1.imag
187  + u.r1c1.real*u.r1c0.imag
188  - u.r1c0.real*u.r1c1.imag) > REAL_EPS ) return 0;
189 
190  return 1;
191 }
192 
194  if ( fabs(alpha.real*alpha.real
195  + alpha.imag*alpha.imag
196  + beta.real*beta.real
197  + beta.imag*beta.imag - 1) > REAL_EPS ) return 0;
198  else return 1;
199 }
200 
202  if ( fabs(sqrt(ux*ux + uy*uy + uz*uz) - 1) > REAL_EPS ) return 0;
203  else return 1;
204 }
205 
207  // init MT random number generator with three keys -- time, pid and a hash of hostname
208  // for the MPI version, it is ok that all procs will get the same seed as random numbers will only be
209  // used by the master process
210 
211  struct timeval tv;
212  gettimeofday(&tv, NULL);
213 
214  double time_in_mill =
215  (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; // convert tv_sec & tv_usec to millisecond
216 
217  unsigned long int pid = getpid();
218  unsigned long int msecs = (unsigned long int) time_in_mill;
219  char hostName[MAXHOSTNAMELEN+1];
220  gethostname(hostName, sizeof(hostName));
221  unsigned long int hostNameInt = hashString(hostName);
222 
223  unsigned long int key[3];
224  key[0] = msecs; key[1] = pid; key[2] = hostNameInt;
225  init_by_array(key, 3);
226 }
227 
231 void QuESTSeedRandom(unsigned long int *seedArray, int numSeeds){
232  // init MT random number generator with user defined list of seeds
233  // for the MPI version, it is ok that all procs will get the same seed as random numbers will only be
234  // used by the master process
235  init_by_array(seedArray, numSeeds);
236 }
237 
238 unsigned long int hashString(char *str){
239  unsigned long int hash = 5381;
240  int c;
241 
242  while ((c = *str++))
243  hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
244 
245  return hash;
246 }
247 
248 #ifdef __cplusplus
249 }
250 #endif
void phaseGate(MultiQubit multiQubit, const int targetQubit, enum phaseGateType type)
void rotateAroundAxis(MultiQubit multiQubit, const int rotQubit, REAL angle, Vector axis)
Rotate a single qubit by a given angle around a given vector on the Bloch-sphere. ...
Definition: QuEST.cpp:91
void reportState(MultiQubit multiQubit)
Print the current state vector of probability amplitudes for a set of qubits to file.
Definition: QuEST.cpp:62
void QuESTSeedRandom(unsigned long int *seedArray, int numSeeds)
numSeeds <= 64
Definition: QuEST.cpp:231
REAL * real
Definition: QuEST.h:20
REAL x
Definition: QuEST.h:42
const char * errorCodes[]
Definition: QuEST.cpp:24
int validateAlphaBeta(Complex alpha, Complex beta)
Definition: QuEST.cpp:193
void rotateX(MultiQubit multiQubit, const int rotQubit, REAL angle)
Rotate a single qubit by a given angle around the X-axis of the Bloch-sphere.
Definition: QuEST.cpp:104
void tGate(MultiQubit multiQubit, const int targetQubit)
Apply the single-qubit T gate.
Definition: QuEST.cpp:163
unsigned long int hashString(char *str)
Definition: QuEST.cpp:238
int numChunks
Number of chunks the state vector is broken up into – the number of MPI processes used...
Definition: QuEST.h:66
void init_by_array(unsigned long init_key[], int key_length)
Definition: mt19937ar.cpp:76
Complex r1c1
Definition: QuEST.h:37
int validateUnitVector(REAL ux, REAL uy, REAL uz)
Definition: QuEST.cpp:201
Definition: QuEST.h:79
The QuEST library API and objects.
Internal functions used to implement the public facing API in qubits.h.
void rotateY(MultiQubit multiQubit, const int rotQubit, REAL angle)
Rotate a single qubit by a given angle around the Y-axis of the Bloch-sphere.
Definition: QuEST.cpp:110
Definition: QuEST.h:79
void QuESTSeedRandomDefault()
Seed the Mersenne Twister used for random number generation in the QuEST environment with an example ...
Definition: QuEST.cpp:206
void controlledCompactUnitary(MultiQubit multiQubit, const int controlQubit, const int targetQubit, Complex alpha, Complex beta)
Apply a controlled unitary (single control, single target) parameterised by two given complex scalars...
Definition: QuEST.h:40
REAL imag
Definition: QuEST.h:29
REAL real
Definition: QuEST.h:28
Complex r0c0
Definition: QuEST.h:36
void compactUnitary(MultiQubit multiQubit, const int rotQubit, Complex alpha, Complex beta)
Apply a single-qubit unitary parameterised by two given complex scalars.
int numQubits
Number of qubits in the state.
Definition: QuEST.h:59
void sGate(MultiQubit multiQubit, const int targetQubit)
Apply the single-qubit S gate.
Definition: QuEST.cpp:158
Definition: QuEST.h:79
void reportMultiQubitParams(MultiQubit multiQubit)
Report metainformation about a set of qubits: number of qubits, number of probability amplitudes...
Definition: QuEST.cpp:80
#define REAL
void rotateZ(MultiQubit multiQubit, const int rotQubit, REAL angle)
Rotate a single qubit by a given angle around the Z-axis of the Bloch-sphere (also known as a phase s...
Definition: QuEST.cpp:116
REAL z
Definition: QuEST.h:42
void sigmaZ(MultiQubit multiQubit, const int targetQubit)
Apply the single-qubit sigma-Z (also known as the Z, Pauli-Z or phase-flip) gate. ...
Definition: QuEST.cpp:153
void controlledRotateX(MultiQubit multiQubit, const int controlQubit, const int targetQubit, REAL angle)
Applies a controlled rotation by a given angle around the X-axis of the Bloch-sphere.
Definition: QuEST.cpp:135
int validateMatrixIsUnitary(ComplexMatrix2 u)
Definition: QuEST.cpp:168
Complex r1c0
Definition: QuEST.h:37
long long int numAmps
Number of probability amplitudes held in stateVec by this process In the non-MPI version, this is the total number of amplitudes.
Definition: QuEST.h:62
#define REAL_EPS
void controlledRotateZ(MultiQubit multiQubit, const int controlQubit, const int targetQubit, REAL angle)
Applies a controlled rotation by a given angle around the Z-axis of the Bloch-sphere.
Definition: QuEST.cpp:147
int chunkId
The position of the chunk of the state vector held by this process in the full state vector...
Definition: QuEST.h:64
Represents a system of qubits.
Definition: QuEST.h:48
void controlledRotateY(MultiQubit multiQubit, const int controlQubit, const int targetQubit, REAL angle)
Applies a controlled rotation by a given angle around the Y-axis of the Bloch-sphere.
Definition: QuEST.cpp:141
void controlledRotateAroundAxis(MultiQubit multiQubit, const int controlQubit, const int targetQubit, REAL angle, Vector axis)
Applies a controlled rotation by a given angle around a given vector on the Bloch-sphere.
Definition: QuEST.cpp:122
Represents a 2x2 matrix of complex numbers.
Definition: QuEST.h:34
REAL y
Definition: QuEST.h:42
REAL * imag
Definition: QuEST.h:21
Represents one complex number.
Definition: QuEST.h:26
Complex r0c1
Definition: QuEST.h:36
ComplexArray stateVec
Probablilty amplitudes for the multi qubit state.
Definition: QuEST.h:51