Appearance
Use Qiskit Runtime in a PlanQK Service
This tutorial shows how to use the Qiskit Runtime SDK together with the IBM Quantum Platform from within a PlanQK Service. As an example, the code will generate some random numbers on the least busy IBM Quantum Platform backend.
Bootstrap Project
- Install the PlanQK CLI.
- Create a new project using
planqk init
and select thePlanQK Starter
template. - Open the project in your IDE of choice, e.g., VSCode.
Create Python Environment
Add the Qiskt Runtime SDK as a dependency to your project by adding qiskit-ibm-runtime
to the requirements.txt
file in the root folder.
You can now set up a Python environment using Conda:
bash
conda env create -f environment.yml
conda activate <environment name>
Conda and the environment.yml
file are used by the PlanQK Platform at runtime. However, if you do not have Conda installed on your local computer, you are also able to initialize a Python virtual environment using the tooling of your choice, e.g., pyenv
or venv
.
You are now able to run the Python src
folder as module from your console:
bash
python3 -m src
Extend Project
Open the program.py
in your IDE. The run()
method is the main handler function and the entry point for your program. The method takes two arguments: (1) a data
dictionary and (2) a params
dictionary holding the input submitted by the user. PlanQK translates the Service API body/payload in the form of { "data": { <data> }, "params": { <params> } }
into these parameters.
It is also important that the run()
method returns a JSON serializable Response
object. The template makes use of the classes ResultResponse
and ErrorResponse
. It's recommended that you use these classes as well.
Next, remove the whole code from within the run()
method.
Add some required import statements:
python
from typing import Dict, Any, Union, cast
from qiskit import QuantumCircuit, transpile
from qiskit_ibm_runtime import QiskitRuntimeService, Session, Sampler
from qiskit_ibm_runtime.accounts import ChannelType
Add the following code to the run()
method:
python
# defines the range of random numbers between 0 and 2^n_bits - 1
n_bits = data.get("n_bits", 2)
channel: ChannelType = cast(ChannelType, os.getenv("QISKIT_IBM_CHANNEL", "ibm_quantum"))
token: str = os.getenv("QISKIT_IBM_TOKEN", None)
instance: str = os.getenv("QISKIT_IBM_INSTANCE", "ibm-q/open/main")
service = QiskitRuntimeService(channel=channel, token=token, instance=instance)
backend = service.least_busy(simulator=False, operational=True)
circuit = QuantumCircuit(n_bits, n_bits)
circuit.h(range(n_bits))
circuit.measure(range(n_bits), range(n_bits))
circuit = transpile(circuit, backend)
start_time = time.time()
with Session(service, backend=backend, max_time=None) as session:
sampler = Sampler(session=session)
job = sampler.run(circuit, shots=10)
job_result = job.result()
execution_time = time.time() - start_time
session.close()
random_number = int(list(job_result.quasi_dists[0].keys())[0])
The code first instantiates the QiskitRuntimeService
using required configuration coming from environment variables. You can use QISKIT_IBM_CHANNEL
to define if you want to use the IBM Quantum Platform (ibm_quantum
) or the IBM Cloud (ibm_cloud
). With QISKIT_IBM_TOKEN
you can specify your respective API token and with QISKIT_IBM_INSTANCE
you can specify the instance string to be used when executing a circuit. The default values from the code above lets you run your program against the IBM Quantum Platform by just setting the QISKIT_IBM_TOKEN
environment variables.
Next, we determine the least busy backend followed by the creation of a simple circuit. By using a Session
, we request a session to run our circuit in. Within this session, we can instantiate a Sampler
and execute the problem by calling sampler.run()
. Finally, we close the session once the result is present, which is when we can extract a random number out of the job result.
Finally, return some result:
python
result = {
"random_number": random_number,
}
metadata = {
"execution_time": round(execution_time, 3),
}
return ResultResponse(result=result, metadata=metadata)
Source Code (program.py)
The full project can be found in our GitLab sample repository.
python
import os
import time
from typing import Dict, Any, Union, cast
from qiskit import QuantumCircuit, transpile
from qiskit_ibm_runtime import QiskitRuntimeService, Session, Sampler
from qiskit_ibm_runtime.accounts import ChannelType
from .libs.return_objects import ResultResponse, ErrorResponse
def run(data: Dict[str, Any] = None, params: Dict[str, Any] = None) -> Union[ResultResponse, ErrorResponse]:
# defines the range of random numbers between 0 and 2^n_bits - 1
n_bits = data.get("n_bits", 2)
# initialize qiskit runtime service
channel: ChannelType = cast(ChannelType, os.getenv("QISKIT_IBM_CHANNEL", "ibm_quantum"))
token: str = os.getenv("QISKIT_IBM_TOKEN", None)
instance: str = os.getenv("QISKIT_IBM_INSTANCE", "ibm-q/open/main")
service = QiskitRuntimeService(channel=channel, token=token, instance=instance)
backend = service.least_busy(simulator=False, operational=True)
# create circuit
circuit = QuantumCircuit(n_bits, n_bits)
circuit.h(range(n_bits))
# perform measurement
circuit.measure(range(n_bits), range(n_bits))
# transpile circuit
circuit = transpile(circuit, backend)
start_time = time.time()
with Session(service, backend=backend, max_time=None) as session:
sampler = Sampler(session=session)
job = sampler.run(circuit, shots=10)
job_result = job.result()
execution_time = time.time() - start_time
session.close()
# extract random number
random_number = int(list(job_result.quasi_dists[0].keys())[0])
result = {
"random_number": random_number,
}
metadata = {
"execution_time": round(execution_time, 3),
}
return ResultResponse(result=result, metadata=metadata)
Run the Project Locally
Run the program using QISKIT_IBM_TOKEN=9356f0193daa... python3 -m src
(copy the API token value from your IBM Quantum Platform account settings).
The output should be similar to the following:
shell
{"result": {"random_number": 8}, "metadata": {"execution_time": 1467.637}}
The project, or the __main__.py
respectively, uses the data.json
and the params.json
as input for the run()
when executed locally. You may experiment with different inputs of the n_bits
input data parameter.
The next section shows how to create and run a PlanQK Service using the code you just have written.
Create a PlanQK Service
We use the PlanQK CLI to create a new service in your personal PlanQK account.
Login with the PlanQK CLI:
shell
planqk login -t <your personal access token>
Create the service:
shell
planqk up
After a while, the console should print something similar like this:
Pushing Image (2/2)... Service created 🚀
Congratulations. You have successfully created a PlanQK Service.
Before you can execute the service, a few more steps are necessary:
- In case you want to run the circuit with a backend offered by the IBM Quantum Platform, you just have to add your respective API token in the Provider Access Tokens settings of your account. In case you want to use the IBM Cloud, you have to add your IBM Cloud credentials by specifying the Service CRN and your API token. Then, PlanQK is able to provide the following environment variables at runtime:
QISKIT_IBM_INSTANCE
(Service CRN value) andQISKIT_IBM_CHANNEL
(constant value: ibm_cloud). - On the PlanQK service overview page, open your service and go to the Runtime Configuration (
Edit Service > Runtime Configuration
). Activate the optionAdd secrets to runtime environment
. This option lets PlanQK inject your API token to the execution runtime. The value is made available through the environment variableQISKIT_IBM_TOKEN
. And in case of IBM Cloud, alsoQISKIT_IBM_INSTANCE
andQISKIT_IBM_CHANNEL
are available at runtime. In your code, you already instrumented theQiskitRuntimeService
accordingly whenever this environment variable is present.
Run your PlanQK Service
Using the PlanQK CLI, you can quickly run a Service Job:
shell
planqk run
The run
command uses the data.json
and params.json
file as input for the job. You may adjust the values accordingly.
Alternatively, you could have created a Service Job through the PlanQK UI. More information about PlanQK Jobs and how to use them can be found in our documentation.
Furthermore, you could also publish your service for internal use and read on how to use the service utilizing PlanQK Applications. Just follow the steps in the Using a Service section in our documentation.