Classical compute demo

Note

Click here to view this tutorial as an interactive Jupyter notebook in IBM Quantum Lab (requires sign-in).

Note

Currently Qiskit is not able to transpile and emit sophisticated control flow to OpenQASM 3. For now, you must write this OpenQASM 3 manually as a source string, as shown below.

This tutorial provides a number of classical compute examples supported from OpenQASM 3, such as, how we can use qubit measurement results to feed-forward, computing intermediate values and modify future operations we apply to the qubits. This is only a subset of capabilities supported by the backends, and as time goes on we will update these tutorials with more detail.

Note

It is not yet possible to perform conditional measurements. This will be coming later in 2022.

Preamble

import os
from typing import Any, List, Dict, Union

import numpy as np
import matplotlib.pyplot as plt

from qiskit import IBMQ, QuantumCircuit, QuantumRegister, ClassicalRegister, execute, quantum_info as qi
from qiskit.providers.ibmq import RunnerResult
from qiskit.result import marginal_counts
import qiskit.tools.jupyter

%matplotlib inline

import warnings
warnings.filterwarnings("ignore")

from run_openqasm3 import run_openqasm3
# Note: This can be any hub/group/project that has access to the required device and the Qiskit runtime.
# Verify that ``qasm3`` is present in ``backend.configuration().supported_features``.
# hub = "<hub>"
# group = "<group>"
# project = "<project>"
# backend_name = "<your backend>"
from qiskit import IBMQ
IBMQ.load_account()
provider = IBMQ.get_provider(hub=hub, group=group, project=project)
backend = provider.get_backend(backend_name)
shots = 1000

Let’s try a program with some classical compute

The tutorial below demonstrates how to perform multiple measurements, assign the results, and compute intermediate classical values with these results that are then used to perform classical conditioned gates.

classical_compute_qasm3 = """

OPENQASM 3.0;

bit a;
bit b;
bit c;
bit meas_and;

x $0;

a = measure $0; // expected "1"
b = measure $1; // expected "0"
c = measure $2; // expected "1"

if (((a | c) & b) == 1) {
    // nested measurements are currently
    // not allowed due to hardware runtime
    // limitations
    //meas_and = measure $0;
    meas_and = 1;
} else {
    //meas_and = measure $1;
    meas_and = 0;
}

bit d;

if (bool(a | b)) {
    d = 1;
} else {
    d = 0;
}

bit e;

if (bool(a ^ b))  {
    e = 1;
} else {
    e = 0;
}

if (e) {
    x $0;
}
bit final;
final = measure $0;
"""
classical_compute_job = run_openqasm3(classical_compute_qasm3, backend, verbose=True, shots=shots)
print(classical_compute_job.job_id())
=======OpenQASM 3======


OPENQASM 3.0;

bit a;
bit b;
bit c;
bit meas_and;

x $0;

a = measure $0; // expected "1"
b = measure $1; // expected "0"
c = measure $2; // expected "1"

if (((a | c) & b) == 1) {
    // nested measurements are currently
    // not allowed due to hardware runtime
    // limitations
    //meas_and = measure $0;
    meas_and = 1;
} else {
    //meas_and = measure $1;
    meas_and = 0;
}

bit d;

if (bool(a | b)) {
    d = 1;
} else {
    d = 0;
}

bit e;

if (bool(a ^ b))  {
    e = 1;
} else {
    e = 0;
}

if (e) {
    x $0;
}
bit final;
final = measure $0;

Running: caosn4lk1m9sjqungblg
==============
{'0': 27, '1': 891, '100': 1, '1000000': 2, '1000001': 48, '1000011': 11, '1000101': 1, '1000111': 1, '101': 18}
caosn4lk1m9sjqungblg
from qiskit.result import Counts
classical_compute_original_counts = classical_compute_job.result().get_counts()
# Assuming you want to pad the counts out to 4 memory slots
classical_compute_new_counts = Counts(classical_compute_original_counts, memory_slots=7)
print(f"Counts: {classical_compute_new_counts}")
# Note you may also specify the `creg_size` argument to add additional creg structure
Counts: {'0000000': 27, '0000001': 891, '0000100': 1, '1000000': 2, '1000001': 48, '1000011': 11, '1000101': 1, '1000111': 1, '0000101': 18}

Bit arrays

The program below shows how we can declare, reference, and assign to bit arrays, and test these array values against integers for conditional execution of gates.

classical_compute_bitstrings = """
OPENQASM 3.0;

bit[4] bitstring = "0110";

bitstring[1] = 1;

qubit $4;
qubit $5;

x $4;

bit parity_result = 1;
bitstring[3] = parity_result;

bitstring[0] = measure $4; // expected "1"

bit b;
b = measure $5; // expected "0"

bitstring[2] = b;

bit[4] another_bitstring = "0000";
bit[4] yet_another;

yet_another = another_bitstring | bitstring;

another_bitstring = another_bitstring | bitstring;

if (another_bitstring == yet_another) {
  x $4;
}
bitstring[3] = measure $4;

"""
classical_compute_bitstrings_job = run_openqasm3(classical_compute_bitstrings, backend, verbose=True, shots=shots)
print(classical_compute_bitstrings_job.job_id())
=======OpenQASM 3======

OPENQASM 3.0;

bit[4] bitstring = "0110";

bitstring[1] = 1;

qubit $4;
qubit $5;

x $4;

bit parity_result = 1;
bitstring[3] = parity_result;

bitstring[0] = measure $4; // expected "1"

bit b;
b = measure $5; // expected "0"

bitstring[2] = b;

bit[4] another_bitstring = "0000";
bit[4] yet_another;

yet_another = another_bitstring | bitstring;

another_bitstring = another_bitstring | bitstring;

if (another_bitstring == yet_another) {
  x $4;
}
bitstring[3] = measure $4;


Running: caosnb7hrqeo3qj6lu3g
==============
{'0': 13, '1': 56, '100001': 1, '101001': 11, '1001': 919}
caosnb7hrqeo3qj6lu3g
classical_compute_bitstrings_original_counts = classical_compute_job.result().get_counts()
# Assuming you want to pad the counts out to 4 memory slots
classical_compute_bitstrings_new_counts = Counts(classical_compute_bitstrings_original_counts, memory_slots=15)
print(f"Counts: {classical_compute_bitstrings_new_counts}")
# Note you may also specify the `creg_size` argument to add additional creg structure
Counts: {'000000000000000': 27, '000000000000001': 891, '000000000000100': 1, '000000001000000': 2, '000000001000001': 48, '000000001000011': 11, '000000001000101': 1, '000000001000111': 1, '000000000000101': 18}
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
qiskit-terra0.21.0
qiskit-aer0.10.4
qiskit-ignis0.7.0
qiskit-ibmq-provider0.20.0.dev0+4f1f8c6
qiskit0.36.1
System information
Python version3.9.5
Python compilerClang 10.0.0
Python builddefault, May 18 2021 12:31:01
OSDarwin
CPUs8
Memory (Gb)32.0
Tue Jun 21 09:52:47 2022 EDT

This code is a part of Qiskit

© Copyright IBM 2017, 2022.

This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.

Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.