Source code for qrisp.interface.provider_backends.iqm_backend

"""
********************************************************************************
* Copyright (c) 2025 the Qrisp authors
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is
* available at https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************
"""

from qrisp.interface import BatchedBackend

[docs] def IQMBackend(api_token, device_instance = None, server_url = None, compilation_options = None, transpiler = None): """ This function creates a :ref:`BatchedBackend` for executing circuits on IQM hardware. Parameters ---------- api_token : str An API token retrieved from the IQM Resonance website or IQM backend. device_instance : str The device instance of the IQM backend such as ``garnet``. For an up-to-date list, see the IQM Resonance website. Required if server_url is not provided. server_url : str, optional The server URL of the IQM backend. If not provided, it defaults to IQM resonance using the device_instance. If a server URL is provided, a device instance should not be provided. compilation_options: CircuitCompilationOptions An object to specify several options regarding `pulse-level compilation <https://docs.meetiqm.com/iqm-client/api/iqm.iqm_client.models.CircuitCompilationOptions.html>`_. transpiler : callable, optional A function receiving and returning a QuantumCircuit, mapping the given circuit to a hardware friendly circuit. By default the `transpile_to_iqm <https://iqm-finland.github.io/qiskit-on-iqm/api/iqm.qiskit_iqm.iqm_naive_move_pass.transpile_to_IQM.html>`_ function will be used. Examples -------- We evaluate a :ref:`QuantumFloat` multiplication on the 20-qubit IQM Garnet. >>> from qrisp.interface import IQMBackend >>> qrisp_garnet = IQMBackend(api_token = "YOUR_IQM_RESONANCE_TOKEN", device_instance = "garnet") >>> from qrisp import QuantumFloat >>> a = QuantumFloat(2) >>> a[:] = 2 >>> b = a*a >>> b.get_measurement(backend = qrisp_garnet, shots = 1000) {4: 0.548, 5: 0.082, 0: 0.063, 6: 0.042, 8: 0.031, 2: 0.029, 12: 0.014, 10: 0.03, 1: 0.027, 7: 0.025, 15: 0.023, 9: 0.021, 14: 0.021, 13: 0.018, 11: 0.014, 3: 0.012} **Manual qubit selection and routing** In the next example we showcase how to prevent automatic selection of qubits. For this we overide the transpilation procedure. The default transpilation calls the ``transpile_to_IQM`` function, which performs routing, automatic selection of suitable qubits, basis-gate transformation and other optimizations. For our example we will just transform to the required basis gates and ensure manually that our circuit has the correct connectivity. :: from qrisp import QuantumCircuit # The custom transpiler should receive and return a QuantumCircuit def custom_transpiler(qc: QuantumCircuit) -> QuantumCircuit: return qc.transpile(basis_gates = ["cz", "r", "measure", "reset"]) custom_transpiled_garnet = IQMBackend("YOUR_IQM_RESONANCE_TOKEN", device_instance = "garnet", transpiler = custom_transpiler) # Create a bell state qc = QuantumCircuit(2) qc.h(0) qc.cx(0, 1) qc.measure(0) # execute meas_res = qc.run(shots = 10000, backend = custom_transpiled_garnet) """ if not isinstance(api_token, str): raise TypeError( "api_token must be a string. You can create an API token on the IQM Resonance website." ) # Validate that either server_url or device_instance is provided, but not both if server_url is not None and device_instance is not None: raise ValueError( "Please provide either a server_url or a device_instance, but not both." ) if server_url is None and device_instance is None: raise ValueError( "Please provide either a server_url or a device_instance." ) if device_instance is not None and not isinstance(device_instance, str): raise TypeError( "device_instance must be a string. You can retrieve a list of available devices on the IQM Resonance website." ) if server_url is not None and not isinstance(server_url, str): raise TypeError( "server_url must be a string." ) try: from iqm.iqm_client.iqm_client import IQMClient from iqm.iqm_client import CircuitCompilationOptions from iqm.qiskit_iqm.iqm_provider import IQMBackend from iqm.qiskit_iqm import transpile_to_IQM except ImportError: raise ImportError( "Please install qiskit-iqm to use the IQMBackend. You can do this by running `pip install qrisp[iqm]`." ) # Construct the server URL based on device_instance if server_url is not provided if server_url is None: server_url = "https://cocos.resonance.meetiqm.com/" + device_instance client = IQMClient(url = server_url, token = api_token) backend = IQMBackend(client) if compilation_options is None: compilation_options = CircuitCompilationOptions() if transpiler is None: def transpiler(qc): from qrisp import QuantumCircuit qiskit_qc = qc.to_qiskit() transpiled_qiskit_qc = transpile_to_IQM(qiskit_qc, backend) return QuantumCircuit.from_qiskit(transpiled_qiskit_qc) def run_batch_iqm(batch): circuit_batch = [] shot_batch = [] for qc, shots in batch: transpiled_qc = transpiler(qc) qiskit_qc = transpiled_qc.to_qiskit() circuit_batch.append(backend.serialize_circuit(qiskit_qc)) if shots is None: shots = 1000 shot_batch.append(shots) UUID = client.submit_circuits(circuit_batch, options = compilation_options, shots = max(shot_batch)) client.wait_for_results(UUID) answer = client.get_run_counts(UUID) import re counts_batch = [] for i in range(len(batch)): counts = answer.counts_batch[i].counts new_counts = {} for key in counts.keys(): counts_string = re.sub(r"\W", "", key) new_counts[counts_string] = counts[key] counts_batch.append(new_counts) return counts_batch return BatchedBackend(run_batch_iqm)