terminal
Docs

Get started with ProjectQ on IonQ Hardware

Last updated: January 31, 2024
IonQ Staff

We are excited to announce official IonQ backend support for ProjectQ, as of version 0.6.1!

With v0.6.1 and later, you can leverage ProjectQ's catalog of compiler backends and intuitive circuit building syntax to run experiments on IonQ's trapped-ion hardware.

About ProjectQ

ProjectQ is an open-source Python framework for quantum computing started at ETH Zurich. The ProjectQ framework combines a highly customizable compiler engine with an abstracted backend model, allowing authors to build quantum circuits that can be run on a variety of simulators, emulators, and real quantum hardware.

If you’re just getting started with ProjectQ, then the official examples and tutorials are great for learning how to write ProjectQ circuits as well as running them against different backends and devices.

Backends in ProjectQ

A ProjectQ Backend is an abstraction used by the framework's compilation engine to process a quantum circuit once it is ready to be run. In addition to real quantum hardware, like IonQ's trapped-ion systems, ProjectQ supports a number of other hardware backends and simulators.

Using the IonQ Backend

Installing the ProjectQ framework

You can install the ProjectQ framework from PyPI, the Python Package Index, using pip:

pip install "projectq>=0.6.1"

We generally recommend using a virtualized Python environment, managed by tools like virtualenv or conda.

Backend and Engine Setup

Building circuits in ProjectQ requires allocating qubits from a compilation engine, which itself requires an execution backend. The code below demonstrates how to create these objects in order to use IonQ as the desired backend:

# Import IonQ's required compiler engine list
import projectq.setups.ionq

# ProjectQ MainEngine
from projectq import MainEngine

# Import IonQ backend class
from projectq.backends import IonQBackend

# An IonQ API token
token = 'token'

# Create and IonQ backend and respective compilers:
device = 'ionq_simulator'
backend = IonQBackend(
    verbose=True,
    token=token,
    device=device,
    num_runs=100,
)
compilers = projectq.setups.ionq.get_engine_list(
    token=token,
    device=device,
)

# Create the main engine:
engine = MainEngine(backend, engine_list=compilers)

The IonQ backend supports both simulator and QPU devices. To see the list of currently available devices, use the IonQ backend's HTTP client:

# Show all supported IonQ devices:
from projectq.backends._ionq import _ionq_http_client
print(_ionq_http_client.show_devices())
{'ionq_simulator': {'nq': 29, 'target': 'simulator'}, 'ionq_qpu': {'nq': 11, 'target': 'qpu'}}

Submitting a Circuit

Once an engine has been created, it can then be used to build and execute quantum circuits. As an example, this is what a simple Bell state circuit looks like using ProjectQ:

from projectq.ops import All, H, CNOT, Measure

# A function to apply a bell state using a ProjectQ engine
def bell_state(eng):
  # Allocate two qubits
  circuit = eng.allocate_qureg(2)
  q0, q1 = circuit
  # Apply a Hadamard gate to the first qubit
  H | q0
  # Then apply a CNOT to both
  CNOT | (q0, q1)
  # Make sure to measure both qubits
  All(Measure) | circuit
  # This submits the circuit to IonQ's API
  eng.flush()
  # Then return the job results
  return eng.backend.get_probabilities(circuit)

# Apply the bell state circuit to our engine
probs = bell_state(engine)

# Print the resulting probabilities
print(probs)
- List of IonQ devices available:
{'ionq_simulator': {'nq': 29, 'target': 'simulator'}, 'ionq_qpu': {'nq': 11, 'target': 'qpu'}}
- Authenticating...
user API token: token
- Running code: {'circuit': [ ... ], 'nq': 2, 'shots': 100, 'meas_mapped': [0, 1]}
- Waiting for results...
Waiting for results. [Job ID: a44f3096-409a-4dce-bcb6-96f50bb7f55f]

...
- Done.
00 with p = 0.5
11 with p = 0.5*
{'00': 0.5, '11': 0.5}

Running on hardware

To run the same circuit on real IonQ hardware (i.e. not a simulator), create the backend and compiler list using the ionq_qpu device:

token = 'token'
device = 'ionq_qpu'  # Use an IonQ QPU device
qpu_backend = IonQBackend(
    verbose=True,
    token=token,
    device=device,
    num_runs=100,
    # Tell the engine to use real hardware
    use_hardware=True,
)
qpu_compilers = projectq.setups.ionq.get_engine_list(
    token=token,
    device=device,
)

# Create a new main engine
qpu_engine = MainEngine(qpu_backend, engine_list=qpu_compilers)

# Then run the bell state circuit against a QPU device
probs = bell_state(qpu_engine)

# Print the resulting probabilities
print(probs)
- List of IonQ devices available:
{'ionq_simulator': {'nq': 29, 'target': 'simulator'}, 'ionq_qpu': {'nq': 11, 'target': 'qpu'}}
- Authenticating...
user API token: token

...
- Done.
00 with p = 0.58*
11 with p = 0.42*
{'00': 0.58, '11': 0.42}

Because QPU time is a limited resource, QPU jobs are handled in a queue and may take a while to complete. The IonQ backend accounts for this delay by providing basic attributes which may be used to tweak the behavior of the backend while it waits on job results:

# Create an IonQ backend with custom job fetch/wait settings
backend = IonQBackend(
    token=token,
    device=device,
    num_runs=100,
    use_hardware=True,
    # Number of times to check for results before giving up
    num_retries=3000,
    # The number of seconds to wait between attempts
    interval=1,
)

Additional resources

The latest ProjectQ documentation can be found here.

As a complement to official documentation, the ProjectQ repository contains a wealth of example circuits, notebooks, and quantum algorithms, similar to the content in this guide.

For more on using ProjectQ, we recommend taking a look at the Code & Docs portion of the ProjectQ website.

Licensing for the ProjectQ framework is Apache 2.0. API keys and access to IonQ services must be obtained under separate terms from IonQ.

The IonQ logo and Q mark are trademarks of IonQ, Inc. Copyright IonQ © 2021. All rights reserved.