Quantum circuits on Rigetti devices

View on QuantumAI Run in Google Colab View source on GitHub Download notebook
try:
    import cirq
except ImportError:
    print("installing cirq...")
    !pip install --quiet cirq
    print("installed cirq.")
    import cirq

Running this notebook requires the pyQuil QVM and Compiler. If you are running on Google Colab or a Linux Debian machine, you can run the below cell to install them if necessary. If you are on a non-Linux Debian machine, see these instructions for installation.

! [ -z "$(which qvm)" ] &&\
  apt update &&\
  apt install jq &&\
  export LATEST_FOREST_SDK_VERSION=$(curl -s https://downloads.rigetti.com/qcs-sdk/versions | jq -r '.versions[0].sdk') &&\
  curl -f https://downloads.rigetti.com/qcs-sdk/forest-sdk-$LATEST_FOREST_SDK_VERSION-linux-deb.tar.bz2 -o $PWD/forest-sdk-$LATEST_FOREST_SDK_VERSION-linux-deb.tar.bz2 &&\
  tar -xf forest-sdk-$LATEST_FOREST_SDK_VERSION-linux-deb.tar.bz2 &&\
  ./forest-sdk-$LATEST_FOREST_SDK_VERSION-linux-deb/forest-sdk-$LATEST_FOREST_SDK_VERSION-linux-deb.run &&\
  quilc --version &&\
  qvm --version
Hit:1 http://archive.ubuntu.com/ubuntu bionic InRelease
Get:2 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]
Get:3 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]
Hit:4 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64  InRelease
Get:5 https://cloud.r-project.org/bin/linux/ubuntu bionic-cran40/ InRelease [3,626 B]
Get:6 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB]
Ign:7 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  InRelease
Hit:8 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  Release
Get:9 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic InRelease [15.9 kB]
Hit:10 http://ppa.launchpad.net/cran/libgit2/ubuntu bionic InRelease
Get:11 http://ppa.launchpad.net/deadsnakes/ppa/ubuntu bionic InRelease [15.9 kB]
Hit:12 http://ppa.launchpad.net/graphics-drivers/ppa/ubuntu bionic InRelease
Get:13 http://security.ubuntu.com/ubuntu bionic-security/universe amd64 Packages [1,512 kB]
Get:14 http://security.ubuntu.com/ubuntu bionic-security/main amd64 Packages [2,799 kB]
Get:15 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages [3,231 kB]
Get:16 http://archive.ubuntu.com/ubuntu bionic-updates/universe amd64 Packages [2,286 kB]
Get:18 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic/main Sources [1,992 kB]
Get:19 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic/main amd64 Packages [1,021 kB]
Get:20 http://ppa.launchpad.net/deadsnakes/ppa/ubuntu bionic/main amd64 Packages [45.3 kB]
Fetched 13.2 MB in 5s (2,876 kB/s)
Reading package lists... Done
Building dependency tree       
Reading state information... Done
45 packages can be upgraded. Run 'apt list --upgradable' to see them.
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following package was automatically installed and is no longer required:
  libnvidia-common-460
Use 'apt autoremove' to remove it.
The following additional packages will be installed:
  libjq1 libonig4
The following NEW packages will be installed:
  jq libjq1 libonig4
0 upgraded, 3 newly installed, 0 to remove and 45 not upgraded.
Need to get 276 kB of archives.
After this operation, 930 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu bionic/universe amd64 libonig4 amd64 6.7.0-1 [119 kB]
Get:2 http://archive.ubuntu.com/ubuntu bionic/universe amd64 libjq1 amd64 1.5+dfsg-2 [111 kB]
Get:3 http://archive.ubuntu.com/ubuntu bionic/universe amd64 jq amd64 1.5+dfsg-2 [45.6 kB]
Fetched 276 kB in 0s (1,212 kB/s)
Selecting previously unselected package libonig4:amd64.
(Reading database ... 155632 files and directories currently installed.)
Preparing to unpack .../libonig4_6.7.0-1_amd64.deb ...
Unpacking libonig4:amd64 (6.7.0-1) ...
Selecting previously unselected package libjq1:amd64.
Preparing to unpack .../libjq1_1.5+dfsg-2_amd64.deb ...
Unpacking libjq1:amd64 (1.5+dfsg-2) ...
Selecting previously unselected package jq.
Preparing to unpack .../jq_1.5+dfsg-2_amd64.deb ...
Unpacking jq (1.5+dfsg-2) ...
Setting up libonig4:amd64 (6.7.0-1) ...
Setting up libjq1:amd64 (1.5+dfsg-2) ...
Setting up jq (1.5+dfsg-2) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
Processing triggers for libc-bin (2.27-3ubuntu1.3) ...
/sbin/ldconfig.real: /usr/local/lib/python3.7/dist-packages/ideep4py/lib/libmkldnn.so.0 is not a symbolic link

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 54.1M  100 54.1M    0     0  25.5M      0  0:00:02  0:00:02 --:--:-- 25.5M
Verifying archive integrity...     0%     7%    14%    22%    29%    37%    44%    51%    59%    66%    74%    81%    89%    96%  100%   MD5 checksums are OK. All good.
Uncompressing forest-sdk-deb     0%     7%    14%    22%    29%    37%    44%    51%    59%    66%    74%    81%    89%    96%  100%  
Reading package lists... Done
Building dependency tree       
Reading state information... Done
libblas-dev is already the newest version (3.7.1-4ubuntu1).
libblas-dev set to manually installed.
liblapack-dev is already the newest version (3.7.1-4ubuntu1).
The following package was automatically installed and is no longer required:
  libnvidia-common-460
Use 'apt autoremove' to remove it.
The following NEW packages will be installed:
  libffi-dev
0 upgraded, 1 newly installed, 0 to remove and 45 not upgraded.
Need to get 156 kB of archives.
After this operation, 362 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu bionic/main amd64 libffi-dev amd64 3.2.1-8 [156 kB]
Fetched 156 kB in 0s (728 kB/s)
Selecting previously unselected package libffi-dev:amd64.
(Reading database ... 155649 files and directories currently installed.)
Preparing to unpack .../libffi-dev_3.2.1-8_amd64.deb ...
Unpacking libffi-dev:amd64 (3.2.1-8) ...
Setting up libffi-dev:amd64 (3.2.1-8) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
Selecting previously unselected package forest-sdk.
(Reading database ... 155684 files and directories currently installed.)
Preparing to unpack forest-sdk_2.23.0.deb ...
Unpacking forest-sdk (2.23.0) ...
Setting up forest-sdk (2.23.0) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
1.23.0 [e6c0939]
1.17.1 [cf3f91f]

Next, run the pyQuil QVM and Compiler if they are not already running on their default ports.

import subprocess

subprocess.Popen(["qvm", "--quiet", "-S"])
subprocess.Popen(["quilc", "--quiet", "-R"])
<subprocess.Popen at 0x7fd6121add10>

Running a Bell state circuit

To demonstrate the basic functionality of the Cirq Rigetti integration, we begin constructing a basic Bell state circuit.

bell_circuit = cirq.Circuit()
qubits = cirq.LineQubit.range(2)
bell_circuit.append(cirq.H(qubits[0]))
bell_circuit.append(cirq.CNOT(qubits[0], qubits[1]))
bell_circuit.append(cirq.measure(qubits[0], qubits[1], key='m'))
print(bell_circuit)
0: ───H───@───M('m')───
          │   │
1: ───────X───M────────

Next, we'll import RigettiQCSService and list available quantum processors.

from cirq_rigetti import RigettiQCSService

quantum_processors = RigettiQCSService.list_quantum_processors().quantum_processors
processors_list = [quantum_processor.id for quantum_processor in quantum_processors]
print(processors_list)
['Aspen-11', 'Aspen-M-1']

For now, we'll instantiate the RigettiQCSService as a pyQuil Quantum Virtual Machine based on the topology of one of the available Rigetti quantum processors. At the time of this writing, Aspen-11 is available.

Note, in addition to the quantum processors listed above, you can also instantiate the RigettiQCSService by naming an arbitrary virtual device the pyQuil QVM supports. See the documentation for pyquil get_qc for more information.

from cirq_rigetti import circuit_transformers, circuit_sweep_executors, get_rigetti_qcs_service

SERVICE_NAME = processors_list[0]
print(SERVICE_NAME)
service = get_rigetti_qcs_service(SERVICE_NAME, as_qvm=True, noisy=False)
result = service.run(bell_circuit, repetitions=1000)

print(result.histogram(key='m'))
Aspen-11
Counter({3: 529, 0: 471})

We'll use the built-in cirq.plot_state_histogram to visually verify the results of our Bell state.

cirq.plot_state_histogram(result.histogram(key='m'))
<matplotlib.axes._subplots.AxesSubplot at 0x7fd610001b10>

png

As expected, we see states 0 (ie '00') and 3 (ie '11') as the dominant results.

You may initialize both the RigettiQCSService and RigettiQCSSampler with execution functions from the cirq_rigetti.circuit_sweep_executor module and transformation functions from cirq_rigetti.circuit_transformations.

You may invoke these functions with arguments for controlling your circuit execution at a more fine grained level. For instance, you may want add Pragma statements to set the initial rewiring strategy, invoke active qubit reset prior to execution, or explicitly address physical qubits on the quantum computer.

from pyquil.quilbase import Reset, Pragma

def hook(program, measurement_id_map):
    program._instructions.insert(0, Reset())
    program._instructions.insert(1, Pragma('INITIAL_REWIRING', freeform_string='GREEDY'))
    print(program)
    return program, measurement_id_map

# assign qubits explicitly to hardware or virtual machine qubits.
qubit_id_map = {
   qubits[0]: 4,
   qubits[1]: 5,
}
executor = circuit_sweep_executors.with_quilc_compilation_and_cirq_parameter_resolution
transformer = circuit_transformers.build(qubit_id_map=qubit_id_map, qubits=qubits, post_transformation_hooks=[hook])
service = get_rigetti_qcs_service(SERVICE_NAME, as_qvm=True, executor=executor, transformer=transformer)
result = service.run(bell_circuit, repetitions=1000)

cirq.plot_state_histogram(result.histogram(key='m'))
RESET
PRAGMA INITIAL_REWIRING "GREEDY"
DECLARE m0 BIT[2]
H 4
CNOT 4 5
MEASURE 4 m0[0]
MEASURE 5 m0[1]
<matplotlib.axes._subplots.AxesSubplot at 0x7fd6110b2150>

png

Running a parameterized circuit

Of course, you may be running a parameterized circuit and would like to leverage the Quil compilers support for parametric compilation. This affords a speedup in execution times as the Cirq Rigetti integration will only compile the circuit once for a single parameter sweep.

We start by initializing the RigettiQCSSampler and specifying a circuit sweep executor that supports parametric compilation. Note, that this class accepts the same executor and transformer types as RigettiQCSService.

from cirq_rigetti import get_rigetti_qcs_sampler

executor = circuit_sweep_executors.with_quilc_parametric_compilation
sampler = get_rigetti_qcs_sampler(SERVICE_NAME, as_qvm=True, executor=executor)

Next, we will initialize a parameterized circuit in Cirq along with a set of parameter values.

import sympy

qubit = cirq.LineQubit.range(1)[0]

circuit = cirq.Circuit(
    cirq.H(qubit)**sympy.Symbol('t'),
    cirq.measure(qubit, key='m'))
params = cirq.Linspace('t', start=0, stop=4, length=5)

print(circuit)
0: ───H^t───M('m')───

In much the same way that we invoke, RigettiQCSSerivce.run, we invoke RigettiQCSSampler.run_sweep with our parameters here.

import pandas as pd

results = sampler.run_sweep(circuit, params, repetitions=10)
data = {f't={result.params["t"]}': [measurement[0] for measurement in result.measurements['m']] for result in results}

pd.DataFrame(data)