Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: compress qubits in multishot #55

Merged
merged 1 commit into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 28 additions & 11 deletions examples/qvm/multishot.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,21 @@ void die(char *msg) {
exit(1);
}

// We specify a base qubit index of 100 in order to ensure
// that QVM compresses the number of qubits used in the program.
// If QVM did not do so, it would fail when trying to allocate
// memory for 100 qubits. In the examples below, QVM only
// really needs to allocate enough memory for 3 qubits.
const int q0 = 100;

void multishot_with_explicit_ro_indices() {
quil_program program;

char *source = "DECLARE ro BIT[3]; X 0; I 1; X 2; MEASURE 0 ro[0]; MEASURE 1 "
"ro[1]; MEASURE 2 ro[2]";
char source[200];
sprintf(source,
"DECLARE ro BIT[3]; X %d; I %d; X %d; MEASURE %d ro[0]; MEASURE %d "
"ro[1]; MEASURE %d ro[2]",
q0, q0 + 1, q0 + 2, q0, q0 + 1, q0 + 2);

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

qvm_multishot_result qvm_res;
int num_trials = 10;
if (qvm_multishot(program, addresses, num_trials, NULL, NULL, NULL, &qvm_res) !=
LIBQUIL_ERROR_SUCCESS) {
if (qvm_multishot(program, addresses, num_trials, NULL, NULL, NULL,
&qvm_res) != LIBQUIL_ERROR_SUCCESS) {
LIBQUIL_ERROR("failed to call qvm_multishot");
exit(1);
}
Expand All @@ -60,8 +70,11 @@ void multishot_with_explicit_ro_indices() {
void multishot_with_implicit_ro_indices() {
quil_program program;

char *source = "DECLARE ro BIT[3]; X 0; I 1; X 2; MEASURE 0 ro[0]; MEASURE 1 "
"ro[1]; MEASURE 2 ro[2]";
char source[200];
sprintf(source,
"DECLARE ro BIT[3]; X %d; I %d; X %d; MEASURE %d ro[0]; MEASURE %d "
"ro[1]; MEASURE %d ro[2]",
q0, q0 + 1, q0 + 2, q0, q0 + 1, q0 + 2);

if (quilc_parse_quil(source, &program) != LIBQUIL_ERROR_SUCCESS) {
LIBQUIL_ERROR("failed to parse quil");
Expand All @@ -83,8 +96,8 @@ void multishot_with_implicit_ro_indices() {
qvm_multishot_result qvm_res;
int num_trials = 10;
double gate_noise[] = {0.0, 0.0, 0.0};
if (qvm_multishot(program, addresses, num_trials, NULL, NULL, NULL, &qvm_res) !=
LIBQUIL_ERROR_SUCCESS) {
if (qvm_multishot(program, addresses, num_trials, NULL, NULL, NULL,
&qvm_res) != LIBQUIL_ERROR_SUCCESS) {
LIBQUIL_ERROR("failed to call qvm_multishot");
exit(1);
}
Expand Down Expand Up @@ -112,8 +125,11 @@ void multishot_with_implicit_ro_indices() {
void multishot_with_noise() {
quil_program program;

char *source = "DECLARE ro BIT[3]; X 0; I 1; X 2; MEASURE 0 ro[0]; MEASURE 1 "
"ro[1]; MEASURE 2 ro[2]";
char source[200];
sprintf(source,
"DECLARE ro BIT[3]; X %d; I %d; X %d; MEASURE %d ro[0]; MEASURE %d "
"ro[1]; MEASURE %d ro[2]",
q0, q0 + 1, q0 + 2, q0, q0 + 1, q0 + 2);

if (quilc_parse_quil(source, &program) != LIBQUIL_ERROR_SUCCESS) {
LIBQUIL_ERROR("failed to parse quil");
Expand All @@ -138,7 +154,8 @@ void multishot_with_noise() {
double gate_noise[] = {0.1, 0.1, 0.1};
double measurement_noise[] = {0.1, 0.0, 0.0};
if (qvm_multishot(program, addresses, num_trials, gate_noise,
measurement_noise, NULL, &qvm_res) != LIBQUIL_ERROR_SUCCESS) {
measurement_noise, NULL,
&qvm_res) != LIBQUIL_ERROR_SUCCESS) {
LIBQUIL_ERROR("failed to call qvm_multishot");
exit(1);
}
Expand Down
8 changes: 5 additions & 3 deletions examples/qvm/wavefunction.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "error.h"
#include "libquil.h"
Expand All @@ -24,14 +24,16 @@ int main(int argc, char **argv) {
int wavefunction_len;
double *wavefunction;
int seed = 0;
if (qvm_wavefunction(program, &seed, &wavefunction, &wavefunction_len) != LIBQUIL_ERROR_SUCCESS) {
if (qvm_wavefunction(program, &seed, &wavefunction, &wavefunction_len) !=
LIBQUIL_ERROR_SUCCESS) {
LIBQUIL_ERROR("failed to call qvm_wavefunction");
exit(1);
}

int n_amplitudes = 4;
for (int i = 0; i < n_amplitudes; i++) {
printf("|%d> = %f + i%f\n", i, wavefunction[i*2], wavefunction[i*2+1]);
printf("|%d> = %f + i%f\n", i, wavefunction[i * 2],
wavefunction[i * 2 + 1]);
}

lisp_release_handle(program);
Expand Down
19 changes: 11 additions & 8 deletions src/qvm/api.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,19 @@

(defun qvm-multishot (compiled-quil addresses trials gate-noise-ptr measurement-noise-ptr rng-seed-ptr)
"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."
(let* ((num-qubits (cl-quil.frontend::qubits-needed compiled-quil))
(let* ((compressed-quil (compress-program-qubits compiled-quil))
(num-qubits (cl-quil.frontend::qubits-needed compressed-quil))
(gate-noise (unless (null-pointer-p gate-noise-ptr)
(unpack-c-array-to-lisp-list gate-noise-ptr 3 :double)))
(measurement-noise (unless (null-pointer-p measurement-noise-ptr)
(unpack-c-array-to-lisp-list measurement-noise-ptr 3 :double)))
(rng-seed (unpack-maybe-nil-pointer rng-seed-ptr :int))
(results
(qvm:with-random-state ((get-random-state rng-seed))
(%perform-multishot compiled-quil num-qubits addresses trials gate-noise measurement-noise))))
(%perform-multishot compressed-quil num-qubits addresses trials gate-noise measurement-noise))))
(make-qvm-multishot-result
:results-map results
:program-memory-descriptors (cl-quil:parsed-program-memory-definitions compiled-quil))))
:program-memory-descriptors (cl-quil:parsed-program-memory-definitions compressed-quil))))

(defun qvm-multishot-result-get (multishot-result address-name shot-index result-pointer)
(let* ((results-map (qvm-multishot-result-results-map multishot-result))
Expand Down Expand Up @@ -85,7 +86,7 @@
(let ((qubits (unpack-c-array-to-lisp-list qubits-ptr n-qubits :int))
(rng-seed (unpack-maybe-nil-pointer rng-seed-ptr :int)))
(multiple-value-bind (compiled-quil relabeling)
(process-quil compiled-quil)
(compress-program-qubits compiled-quil)
(let* ((num-qubits (cl-quil:qubits-needed compiled-quil))
(results
(qvm:with-random-state ((get-random-state rng-seed))
Expand Down Expand Up @@ -120,10 +121,11 @@
expectation))))

(defun qvm-wavefunction (program rng-seed-ptr results-ptr results-len-ptr)
(let* ((num-qubits (cl-quil:qubits-needed program))
(let* ((compressed-program (compress-program-qubits program))
(num-qubits (cl-quil:qubits-needed compressed-program))
(rng-seed (unpack-maybe-nil-pointer rng-seed-ptr :int))
(qvm (qvm:with-random-state ((get-random-state rng-seed))
(%execute-quil program num-qubits nil nil)))
(%execute-quil compressed-program num-qubits nil nil)))
(amplitudes (qvm::amplitudes qvm))
(amplitude-pairs
(alexandria:flatten
Expand All @@ -136,11 +138,12 @@
(length amplitude-pairs))))

(defun qvm-probabilities (program rng-seed-ptr results-ptr)
(let* ((num-qubits (cl-quil:qubits-needed program))
(let* ((compressed-program (compress-program-qubits program))
(num-qubits (cl-quil:qubits-needed compressed-program))
(rng-seed (unpack-maybe-nil-pointer rng-seed-ptr :int))
(probabilities (multiple-value-bind (_ probabilities)
(qvm:with-random-state ((get-random-state rng-seed))
(%perform-probabilities program num-qubits))
(%perform-probabilities compressed-program num-qubits))
(declare (ignore _))
probabilities)))
(loop :for probability :across probabilities
Expand Down
23 changes: 10 additions & 13 deletions src/qvm/qvm-app-imports.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@
:test #'string= :documentation "The git hash of the QVM repo.")
)

(defun compress-program-qubits (quil)
(let* ((quil (cl-quil:copy-instance quil))
(trivial-mapping-p
(loop :for x :across (cl-quil::compute-qubit-mapping quil)
:for i :from 0
:always (= x i))))
(unless trivial-mapping-p
(cl-quil::transform 'cl-quil::compress-qubits quil))
quil))

(defun get-random-state (arg)
(etypecase arg
(null (qvm:seeded-random-state nil))
Expand Down Expand Up @@ -226,19 +236,6 @@ single qubit readout povm.
(reload qvm)
(parallel-measure qvm qubits)))))))

(defun process-quil (quil)
"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.

The mapping vector V specifies that the qubit as specified in the program V[i] has been mapped to qubit i."
(let* ((mapping (cl-quil::compute-qubit-mapping quil))
(trivial-mapping-p
(loop :for x :across mapping
:for i :from 0
:always (= x i))))
(unless trivial-mapping-p
(cl-quil::transform 'cl-quil::compress-qubits quil))
(values quil mapping)))

(defun valid-address-query-p (addresses)
(cond
((not (hash-table-p addresses)) nil)
Expand Down
Loading