import os
from iqm.qiskit_iqm import IQMProvider
from qiskit import QuantumCircuit, transpile
Example: Using VTT QX to Submit Jobs
Step 1: Installing Python library dependencies
This notebook requires a Python virtual environment with following libraries installed. Please refer to the Devices page; Q5 and Q50, or check VTT QX to find the latest library versions.
The following packages listed below could be saved as requirements.txt
:
iqm-client==20.17
qiskit-iqm==15.6
matplotlib
pylatexenc
First, create a virtual Python environment with
conda create -n vttqx python=3.11 pip
conda activate vttqx
Then install the dependencies with
pip install iqm-client==20.17 qiskit-iqm==15.6 matplotlib pylatexenc
If you prefer using uv
for faster installs and reproducible builds:
# Initialize a new project
uv init
# This creates a pyproject.toml file for project configuration
# Then installs dependencies, which will be recorded
uv add iqm-client==20.17 qiskit-iqm==15.6 matplotlib pylatexenc
# Or install from existing requirements
uv pip install -r requirements.txt
Starting Jupyter Notebook
Install Jupyter in your conda environment:
conda activate vttqx
pip install notebook
# Start Jupyter Notebook
jupyter notebook
Install and run Jupyter in your uv-managed environment:
# First, activate your uv environment
source vttqx/bin/activate # On Windows: vttqx\Scripts\activate
# Install Jupyter
uv pip install notebook
# Start Jupyter Notebook
jupyter notebook
Then we can import the IQM client library and the qiskit
Python objects to define a quantum circuit
Step 2: Define your quantum circuit
Next, we define a quantum circuit that prepares a so called Bell state. In the first line we instantiate a QuantumCircuit
object, that allocates two qubits. Further more, we give it the name Bell pair circuit
.
= QuantumCircuit(2, name="Bell pair circuit")
circuit 0) # Apply a Hadamard gate to the first qubit
circuit.h(
circuit.cx(0, 1
# Apply a CNOT gate withfirst qubit as control qubit and second as target qubit
) # Finally, we add a measurement operation measuring all qubits
circuit.measure_all() ="mpl") circuit.draw(output
Step 3. How to submit to VTT QX?
To submit to VTT QX, we have to instantiate the IQMProvider
, which takes a server URL as an argument. The URL should expose all needed API endpoints to fetch information about the target quantum computer. In the picture below, it is shown how to fetch the server URL for the Q5 quantum computer in the VTT QX UI.
= "https://qx.vtt.fi/api/devices/q5"
server_url = IQMProvider(server_url) provider
Generate project token
The provider allows us to generate a qiskit Backend object, that describes the quantum architecture that we are targeting. Knowing the details of the target quantum architecture is important for transpilation of our quantum circuits to the native gates and topology of the target device.
To instantiate the backend, the provider will make a call to the server_url
, requesting information about the backend. VTT QX requires, that this call is authenticated. A user authenticates itself to VTT QX, by attaching a project token to each request. The project token can be copied from the dashboard in VTT QX.
Select the project as shown in the picture above. Next, copy the token following the instructions above
Alternatively, you can generate a new project token by authenticating with an existing active project token. This method is useful when you already have access to a project and want to rotate or generate additional tokens. You can do this by using the following curl
command:
curl 'https://qx.vtt.fi/api/projects/{project_id}/token' \
-X POST \
-H 'Authorization: Bearer <active_project_token>' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json'
Finally, paste the token into the cell below. The token is exposed to the IQM client via the environment variable IQM_TOKEN
.
# Set the VTT QX token
"IQM_TOKEN"] = "<token-here>"
os.environ[
# Note, the token can also be passed directly to the client with out setting IQM_TOKEN
# provider = IQMProvider(server_url, token="<token-here>")
Now, we can generate a backend object, which allows us to print more information about our target device
= provider.get_backend()
backend
print(f"Native operations: {backend.operation_names}")
print(f"Number of qubits: {backend.num_qubits}")
print(f"Coupling map: {backend.coupling_map}")
Before executing the circuit, we need to make sure that it only consists of native gates supported by the device
= transpile(circuit, backend) transpiled_circuit
Finally, we can also submit the quantum circuit that we defined at the beginning and print the results
for _ in range(1):
= backend.run(transpiled_circuit)
job = job.result().get_counts()
counts print(counts)
Step 4: Inspecting job results in VTT QX
VTT QX exposes additional information about the job in the UI.
Optional: Submitting with Cirq
IQM Cirq user guide can be found here: IQM-Cirq
⚠️ ⚠️ Cirq is not as well supported by IQM as Qiskit ⚠️ ⚠️
Compatible versions:
cirq-iqm 15.3
cirq-core 1.4.1
import cirq
from iqm.cirq_iqm import Adonis
= Adonis()
adonis
# Print metadata about the chip
print(adonis.metadata.qubit_set)
print(adonis.metadata.gateset)
print(adonis.metadata.nx_graph)
# Define a test circuit with 2 qubits
= cirq.NamedQubit("Alice"), cirq.NamedQubit("Bob")
q1, q2 = cirq.Circuit()
circuit
circuit.append(cirq.X(q1))
circuit.append(cirq.H(q2))
circuit.append(cirq.CNOT(q1, q2))="m"))
circuit.append(cirq.measure(q1, q2, keyprint(circuit)
from iqm.cirq_iqm.iqm_sampler import IQMSampler
# Decompose circuit to native gate set
= adonis.decompose_circuit(circuit)
decomposed_circuit # Map logical qubits to physical qubits and insert SWAP gates where needed
= adonis.route_circuit(
routed_circuit_1, initial_mapping, final_mapping
decomposed_circuit
)
# Use the `IQMSampler` class to perform authenticated circuit submission
= IQMSampler(server_url)
sampler = sampler.run(routed_circuit_1, repetitions=10)
result print(result.measurements["m"])