Skip to content

Commit 2d16ecd

Browse files
authored
fix: compress qubits in multishot (#55)
1 parent be76673 commit 2d16ecd

File tree

4 files changed

+54
-35
lines changed

4 files changed

+54
-35
lines changed

examples/qvm/multishot.c

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,21 @@ void die(char *msg) {
1010
exit(1);
1111
}
1212

13+
// We specify a base qubit index of 100 in order to ensure
14+
// that QVM compresses the number of qubits used in the program.
15+
// If QVM did not do so, it would fail when trying to allocate
16+
// memory for 100 qubits. In the examples below, QVM only
17+
// really needs to allocate enough memory for 3 qubits.
18+
const int q0 = 100;
19+
1320
void multishot_with_explicit_ro_indices() {
1421
quil_program program;
1522

16-
char *source = "DECLARE ro BIT[3]; X 0; I 1; X 2; MEASURE 0 ro[0]; MEASURE 1 "
17-
"ro[1]; MEASURE 2 ro[2]";
23+
char source[200];
24+
sprintf(source,
25+
"DECLARE ro BIT[3]; X %d; I %d; X %d; MEASURE %d ro[0]; MEASURE %d "
26+
"ro[1]; MEASURE %d ro[2]",
27+
q0, q0 + 1, q0 + 2, q0, q0 + 1, q0 + 2);
1828

1929
if (quilc_parse_quil(source, &program) != LIBQUIL_ERROR_SUCCESS) {
2030
LIBQUIL_ERROR("failed to parse quil");
@@ -36,8 +46,8 @@ void multishot_with_explicit_ro_indices() {
3646

3747
qvm_multishot_result qvm_res;
3848
int num_trials = 10;
39-
if (qvm_multishot(program, addresses, num_trials, NULL, NULL, NULL, &qvm_res) !=
40-
LIBQUIL_ERROR_SUCCESS) {
49+
if (qvm_multishot(program, addresses, num_trials, NULL, NULL, NULL,
50+
&qvm_res) != LIBQUIL_ERROR_SUCCESS) {
4151
LIBQUIL_ERROR("failed to call qvm_multishot");
4252
exit(1);
4353
}
@@ -60,8 +70,11 @@ void multishot_with_explicit_ro_indices() {
6070
void multishot_with_implicit_ro_indices() {
6171
quil_program program;
6272

63-
char *source = "DECLARE ro BIT[3]; X 0; I 1; X 2; MEASURE 0 ro[0]; MEASURE 1 "
64-
"ro[1]; MEASURE 2 ro[2]";
73+
char source[200];
74+
sprintf(source,
75+
"DECLARE ro BIT[3]; X %d; I %d; X %d; MEASURE %d ro[0]; MEASURE %d "
76+
"ro[1]; MEASURE %d ro[2]",
77+
q0, q0 + 1, q0 + 2, q0, q0 + 1, q0 + 2);
6578

6679
if (quilc_parse_quil(source, &program) != LIBQUIL_ERROR_SUCCESS) {
6780
LIBQUIL_ERROR("failed to parse quil");
@@ -83,8 +96,8 @@ void multishot_with_implicit_ro_indices() {
8396
qvm_multishot_result qvm_res;
8497
int num_trials = 10;
8598
double gate_noise[] = {0.0, 0.0, 0.0};
86-
if (qvm_multishot(program, addresses, num_trials, NULL, NULL, NULL, &qvm_res) !=
87-
LIBQUIL_ERROR_SUCCESS) {
99+
if (qvm_multishot(program, addresses, num_trials, NULL, NULL, NULL,
100+
&qvm_res) != LIBQUIL_ERROR_SUCCESS) {
88101
LIBQUIL_ERROR("failed to call qvm_multishot");
89102
exit(1);
90103
}
@@ -112,8 +125,11 @@ void multishot_with_implicit_ro_indices() {
112125
void multishot_with_noise() {
113126
quil_program program;
114127

115-
char *source = "DECLARE ro BIT[3]; X 0; I 1; X 2; MEASURE 0 ro[0]; MEASURE 1 "
116-
"ro[1]; MEASURE 2 ro[2]";
128+
char source[200];
129+
sprintf(source,
130+
"DECLARE ro BIT[3]; X %d; I %d; X %d; MEASURE %d ro[0]; MEASURE %d "
131+
"ro[1]; MEASURE %d ro[2]",
132+
q0, q0 + 1, q0 + 2, q0, q0 + 1, q0 + 2);
117133

118134
if (quilc_parse_quil(source, &program) != LIBQUIL_ERROR_SUCCESS) {
119135
LIBQUIL_ERROR("failed to parse quil");
@@ -138,7 +154,8 @@ void multishot_with_noise() {
138154
double gate_noise[] = {0.1, 0.1, 0.1};
139155
double measurement_noise[] = {0.1, 0.0, 0.0};
140156
if (qvm_multishot(program, addresses, num_trials, gate_noise,
141-
measurement_noise, NULL, &qvm_res) != LIBQUIL_ERROR_SUCCESS) {
157+
measurement_noise, NULL,
158+
&qvm_res) != LIBQUIL_ERROR_SUCCESS) {
142159
LIBQUIL_ERROR("failed to call qvm_multishot");
143160
exit(1);
144161
}

examples/qvm/wavefunction.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
#include <math.h>
12
#include <stdio.h>
23
#include <stdlib.h>
34
#include <string.h>
4-
#include <math.h>
55

66
#include "error.h"
77
#include "libquil.h"
@@ -24,14 +24,16 @@ int main(int argc, char **argv) {
2424
int wavefunction_len;
2525
double *wavefunction;
2626
int seed = 0;
27-
if (qvm_wavefunction(program, &seed, &wavefunction, &wavefunction_len) != LIBQUIL_ERROR_SUCCESS) {
27+
if (qvm_wavefunction(program, &seed, &wavefunction, &wavefunction_len) !=
28+
LIBQUIL_ERROR_SUCCESS) {
2829
LIBQUIL_ERROR("failed to call qvm_wavefunction");
2930
exit(1);
3031
}
3132

3233
int n_amplitudes = 4;
3334
for (int i = 0; i < n_amplitudes; i++) {
34-
printf("|%d> = %f + i%f\n", i, wavefunction[i*2], wavefunction[i*2+1]);
35+
printf("|%d> = %f + i%f\n", i, wavefunction[i * 2],
36+
wavefunction[i * 2 + 1]);
3537
}
3638

3739
lisp_release_handle(program);

src/qvm/api.lisp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,19 @@
3434

3535
(defun qvm-multishot (compiled-quil addresses trials gate-noise-ptr measurement-noise-ptr rng-seed-ptr)
3636
"Executes COMPILED-QUIL on a pure-state QVM TRIALS numbers of times. At the end of each execution, the measurements for ADDRESSES are collected. The return value is a list of those measurements."
37-
(let* ((num-qubits (cl-quil.frontend::qubits-needed compiled-quil))
37+
(let* ((compressed-quil (compress-program-qubits compiled-quil))
38+
(num-qubits (cl-quil.frontend::qubits-needed compressed-quil))
3839
(gate-noise (unless (null-pointer-p gate-noise-ptr)
3940
(unpack-c-array-to-lisp-list gate-noise-ptr 3 :double)))
4041
(measurement-noise (unless (null-pointer-p measurement-noise-ptr)
4142
(unpack-c-array-to-lisp-list measurement-noise-ptr 3 :double)))
4243
(rng-seed (unpack-maybe-nil-pointer rng-seed-ptr :int))
4344
(results
4445
(qvm:with-random-state ((get-random-state rng-seed))
45-
(%perform-multishot compiled-quil num-qubits addresses trials gate-noise measurement-noise))))
46+
(%perform-multishot compressed-quil num-qubits addresses trials gate-noise measurement-noise))))
4647
(make-qvm-multishot-result
4748
:results-map results
48-
:program-memory-descriptors (cl-quil:parsed-program-memory-definitions compiled-quil))))
49+
:program-memory-descriptors (cl-quil:parsed-program-memory-definitions compressed-quil))))
4950

5051
(defun qvm-multishot-result-get (multishot-result address-name shot-index result-pointer)
5152
(let* ((results-map (qvm-multishot-result-results-map multishot-result))
@@ -85,7 +86,7 @@
8586
(let ((qubits (unpack-c-array-to-lisp-list qubits-ptr n-qubits :int))
8687
(rng-seed (unpack-maybe-nil-pointer rng-seed-ptr :int)))
8788
(multiple-value-bind (compiled-quil relabeling)
88-
(process-quil compiled-quil)
89+
(compress-program-qubits compiled-quil)
8990
(let* ((num-qubits (cl-quil:qubits-needed compiled-quil))
9091
(results
9192
(qvm:with-random-state ((get-random-state rng-seed))
@@ -120,10 +121,11 @@
120121
expectation))))
121122

122123
(defun qvm-wavefunction (program rng-seed-ptr results-ptr results-len-ptr)
123-
(let* ((num-qubits (cl-quil:qubits-needed program))
124+
(let* ((compressed-program (compress-program-qubits program))
125+
(num-qubits (cl-quil:qubits-needed compressed-program))
124126
(rng-seed (unpack-maybe-nil-pointer rng-seed-ptr :int))
125127
(qvm (qvm:with-random-state ((get-random-state rng-seed))
126-
(%execute-quil program num-qubits nil nil)))
128+
(%execute-quil compressed-program num-qubits nil nil)))
127129
(amplitudes (qvm::amplitudes qvm))
128130
(amplitude-pairs
129131
(alexandria:flatten
@@ -136,11 +138,12 @@
136138
(length amplitude-pairs))))
137139

138140
(defun qvm-probabilities (program rng-seed-ptr results-ptr)
139-
(let* ((num-qubits (cl-quil:qubits-needed program))
141+
(let* ((compressed-program (compress-program-qubits program))
142+
(num-qubits (cl-quil:qubits-needed compressed-program))
140143
(rng-seed (unpack-maybe-nil-pointer rng-seed-ptr :int))
141144
(probabilities (multiple-value-bind (_ probabilities)
142145
(qvm:with-random-state ((get-random-state rng-seed))
143-
(%perform-probabilities program num-qubits))
146+
(%perform-probabilities compressed-program num-qubits))
144147
(declare (ignore _))
145148
probabilities)))
146149
(loop :for probability :across probabilities

src/qvm/qvm-app-imports.lisp

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@
1111
:test #'string= :documentation "The git hash of the QVM repo.")
1212
)
1313

14+
(defun compress-program-qubits (quil)
15+
(let* ((quil (cl-quil:copy-instance quil))
16+
(trivial-mapping-p
17+
(loop :for x :across (cl-quil::compute-qubit-mapping quil)
18+
:for i :from 0
19+
:always (= x i))))
20+
(unless trivial-mapping-p
21+
(cl-quil::transform 'cl-quil::compress-qubits quil))
22+
quil))
23+
1424
(defun get-random-state (arg)
1525
(etypecase arg
1626
(null (qvm:seeded-random-state nil))
@@ -226,19 +236,6 @@ single qubit readout povm.
226236
(reload qvm)
227237
(parallel-measure qvm qubits)))))))
228238

229-
(defun process-quil (quil)
230-
"Prepare the PARSED-PROGRAM QUIL for more efficient execution. Currently this only includes remapping the qubits to a minimal sequential set from 0 to (num-qubits-used - 1). Return two values: the processed Quil code and the mapping vector.
231-
232-
The mapping vector V specifies that the qubit as specified in the program V[i] has been mapped to qubit i."
233-
(let* ((mapping (cl-quil::compute-qubit-mapping quil))
234-
(trivial-mapping-p
235-
(loop :for x :across mapping
236-
:for i :from 0
237-
:always (= x i))))
238-
(unless trivial-mapping-p
239-
(cl-quil::transform 'cl-quil::compress-qubits quil))
240-
(values quil mapping)))
241-
242239
(defun valid-address-query-p (addresses)
243240
(cond
244241
((not (hash-table-p addresses)) nil)

0 commit comments

Comments
 (0)