Using Qiskit with Quantinuum Devices¶
Qiskit is a popular tool for quantum computing programmers. qiskit
circuits can be converted to TKET circuits and submitted to Nexus for execution on Quantinuum Systems. Similar TKET workflows for submitting to Quantinuum devices exist for other programming interfaces such as cirq
or Q#. For more information, see here.
Note
Not all capabilities for Quantinuum devices available via pytket
are guaranteed to be available in qiskit
. Some use cases may require working directly in pytket.
Installation
Qiskit and pytket-qiskit (interface from TKET
to qiskit
) can be installed with the command below. Additionally, qnexus
, the client-tool to programmatically submit and view resources in Nexus needs to be installed.
pip install pytket-qiskit pytket qnexus
Qiskit to TKET circuit conversion¶
When working with qiskit
, quantum circuits are created using Qiskit’s QuantumCircuit
object.
To submit to Quantinuum devices with Nexus, the Qiskit QuantumCircuit
object needs to be converted to a Pytket Circuit
object. This is done via the qiskit_to_tk
function. Quantum circuits can be converted between Qiskit and Pytket options via the qiskit_to_tk
and tk_to_qiskit
functions.
from qiskit import QuantumCircuit
n_qubits = 2
circuit = QuantumCircuit(n_qubits, n_qubits, name="Bell Test")
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
from pytket.extensions.qiskit import qiskit_to_tk
tket_circuit = qiskit_to_tk(circuit)
Nexus Project Setup¶
Nexus workflows require a Project to be initialized. If a Nexus project already exists it can be retrieved from the Nexus database. Once the project has been initialized, it can be set as the default project in the current python session.
import qnexus as qnx
import datetime
project = qnx.projects.get_or_create("Qiskit Conversion")
qnx.context.set_active_project(project)
name_suffix = datetime.datetime.now().strftime("%Y_%m_%d")
The qnexus.QuantinuumConfig
allows the user to specify the target resource to use for compilation and execution. Additional provider specific options can be specified here.
config = qnx.QuantinuumConfig(device_name="H1-Emulator")
The circuit to be compiled and executed needs to be uploaded to the Nexus database using . This will output a circuit reference instance.
ref_circuit = qnx.circuits.upload(
circuit=tket_circuit,
name=f"precompiled-tket-circuit-{name_suffix}",
)
Compile Job¶
The circuit reference and the QuantinuumConfig
instance are inputted into . In addition, the keyword arguments optimisation_level
and name
need to be specified.
optimisation_level
: An integer specifying the level of circuit optimisation.2
is the maximum value and0
is the minimum value.name
: A user-friendly name to assign to the compile job. This is unique within the scope of the Nexus Project.
start_compile_job
will output a Job reference. This reference can be used to query job status and request results from Nexus.
ref_compile_job = qnx.start_compile_job(
circuits=[ref_circuit],
optimisation_level=0,
backend_config=config,
name=f"compile-job-{name_suffix}"
)
The request to retrieve results can be blocked using . Once the result is available for request, can be used to retrieve a list of result references. get_output
will output the the circuit reference for the compiled circuit.
qnx.jobs.wait_for(ref_compile_job)
ref_compiled_circuit = qnx.jobs.results(ref_compile_job)[0].get_output()
The compiled circuit can be downloaded to the current python session using download_circuit
. This outputs a pytket.ciruit.Circuit
instance. The commands in the compiled circuit are printed using .
compiled_circuit = ref_compiled_circuit.download_circuit()
compiled_circuit.get_commands()
Job Costing¶
The number of HQCs required can be estimated using . This function requires the circuit reference for the compiled circuit, the number of shots to be used for the execute job. The backend_config
needs to use a QuantinuumConfig
instance targetting hardware. QuantinuumConfig
instances targetting a Nexus-hosted emulator do not consume HQCs, but rather have a Nexus classical compute time quota.
n_shots = 100
h1_cost = qnx.client.circuits.cost(
ref_compiled_circuit,
n_shots=n_shots,
backend_config=qnx.QuantinuumConfig(device_name="H1-1")
)
print(f"Cost: {h1_cost} HQC")
Execute Job¶
The circuit reference and the QuantinuumConfig
instance are inputted into . In addition, the keyword arguments n_shots
and name
need to be specified.
n_shots
: An integer specifying the number of shots needed to build a distribution of measurement results for the circuit submitted to the system or emulator.name
: A user-friendly name to assign to the execute job. This is unique within the scope of the Nexus Project.
start_execute_job
will output a Job reference. This reference can be used to query job status and request results from Nexus.
ref_execute_job = qnx.start_execute_job(
circuits=[ref_compiled_circuit],
backend_config=config,
n_shots=[n_shots],
name=f"execute-job-{name_suffix}"
)
The request to retrieve results can be blocked using . Once the result is available for request, can be used to retrieve a list of result references.
qnx.jobs.wait_for(ref_execute_job)
ref_result = qnx.jobs.results(ref_execute_job)[0]
The results from the execute job can be downloaded to the current python session using download_result
. This will return an instance of tket:pytket.backend.backendresult.BackendResult.
result = ref_result.download_result()
The pandas dataframe below reports the measurement result as a probability distribution. The index reports the measured bit string and the column entry reports probability of occurance.
from pandas import DataFrame
distribution = result.get_distribution()
df = DataFrame(distribution.values(), index=list(distribution.keys()), columns=["Probability"])
df