Repository navigation
Expand file tree
/
Copy pathqft.cpp
More file actions
116 lines (97 loc) · 3.4 KB
/
Copy pathqft.cpp
File metadata and controls
116 lines (97 loc) · 3.4 KB
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <cuComplex.h>
#include "qft_gpu_launch.h"
#include "quantum_utils.h"
#include "Stopwatch.h"
#define THREADS_PER_BLOCK 512
void make_test_vector(int width, cuDoubleComplex **v){
if (*v) {
free(*v);
}
unsigned long long N = (1ull << width);
*v = (cuDoubleComplex*)calloc(N, sizeof(cuDoubleComplex));
if (!*v) {
fprintf(stderr, "Error allocating memory for vector (size %llu).\n", N);
exit(1);
}
// Initialize a test vector.
// This isn't normalized. In a normalized test vector, some elements
// would be very small. libquantum discards low-probability entries during its
// calculations. This creates "false" error between libquantum's output and ours.
unsigned long long i;
for (i = 0; i < N; i++) {
(*v)[i].x = 1.0f/float(i+1) + 1e-5f;
(*v)[i].y = 1.0f/float(i+1) + 1e-5f;
}
}
int qft_test(int argc, char *argv[]){
// Get the number of qubits from the user, or use 8 as the default.
int width = 8;
if (argc >= 1) {
width = atoi(argv[0]);
}
// Get the GPU version from the user or use the latest as the default.
QFT_versions version = QFT_BEST;
if (argc >= 2) {
version = (QFT_versions)atoi(argv[1]);
}
if (version == QFT_v0_HOST) {
printf("Using GPU-QFT version: 0 (HOST reference implementation)\n");
} else {
printf("Using GPU-QFT version: %d\n", (int)version);
}
double vecsize = double(sizeof(cuDoubleComplex))*double(1ull<<width)/1024.0/1024.0;
printf("Width: %d qubits (%llu states, %f MB).\n", width, 1ull<<width, vecsize);
Stopwatch s(false); // measure CPU time
// Make a new test vector and copy it into the output vector.
// (The output vector will be modified in-place.)
cuDoubleComplex *vin = NULL, *vout = NULL, *vtmp = NULL;
make_test_vector(width, &vin);
qutil_new_qvec(width, &vout);
quantum_reg qr = qutil_collapse_qr(width, vin);
qutil_copy_qvec(&vout, vin, width);
// Time the GPU implementation.
double time_gpu = qft_gpu(width, vout, THREADS_PER_BLOCK, version);
printf("GPU time: %f ms.\n", time_gpu*1000.0);
fflush(stdout);
// Time libquantum's implementation.
s.restart();
quantum_qft(width, &qr);
double time_libq = s.getElapsed();
printf("Libquantum: %f ms.\n", time_libq*1000.0);
fflush(stdout);
// Bandingkan waktu
printf("Speedup: %f x\n", time_libq/time_gpu);
// Compare the output vectors.
printf("Preparing vectors for comparison...\n");
// To save memory, we clean up arrays and quregs we don't need.
qutil_destroy_qvec(&vin);
// Expand libquantum's vector for comparison.
qutil_expand_qr(qr, &vtmp);
quantum_delete_qureg(&qr);
// Collapse and re-expand the GPU vector.
// libquantum deletes "small" states automatically. If we don't do the same,
// then the comparison will be skewed.
quantum_reg qr_tmp = qutil_collapse_qr(width, vout);
qutil_expand_qr(qr_tmp, &vout);
printf("l2norm = %f\n", qutil_l2norm_qvecs(width, vout, vtmp));
// Clean up the remaining vectors.
qutil_destroy_qvec(&vout);
qutil_destroy_qvec(&vtmp);
return 0;
}
static void printUsage(){
printf("Usage: qft B [V]\n");
printf(" tests the QFT algorithm using B qubits and version V of the GPU algorithm.\n");
printf(" V should be from 0 to 6. The default value is %d.\n", (int)QFT_BEST);
}
int main(int argc, char *argv[]){
if (argc == 1) {
printUsage();
return 1;
} else {
return qft_test(argc-1, argv+1);
}
}