Source code for qoqo_qiskit.interface.interface

# Copyright © 2023 HQS Quantum Simulations GmbH.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
# in compliance with the License. You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
# or implied. See the License for the specific language governing permissions and limitations under
# the License.
"""Qiskit interface for qoqo circuits."""

from qoqo import Circuit
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister

from qoqo_qasm import QasmBackend

from typing import Tuple, Optional, Dict, Any


[docs] def to_qiskit_circuit( circuit: Circuit, qubit_register_name: Optional[str] = None ) -> Tuple[QuantumCircuit, Dict[str, int]]: """Applies the qoqo Circuit -> Qiskit QuantumCircuit conversion. Args: circuit (Circuit): the qoqo Circuit to port. qubit_register_name (Optional[str]): the name of the qubit register. Returns: Tuple[QuantumCircuit, Dict[str, int]]: equivalent QuantumCircuit and dict\ containing info for Qiskit's backend. Raises: ValueError: the circuit contains a symbolic PragmaLoop operation. """ # Populating dict output. Currently handling: # - PragmaSetStateVector (continues further down) # - PragmaGetStateVector # - PragmaGetDensityMatrix # - PragmaSetNumberOfMeasurement # - PragmaRepeatedMeasurement # - PragmaLoop # - MeasureQubit filtered_circuit = Circuit() to_fix = False circuit_info: Dict[str, Any] = {} circuit_info["MeasurementInfo"] = {} circuit_info["SimulationInfo"] = {} circuit_info["SimulationInfo"]["PragmaGetStateVector"] = False circuit_info["SimulationInfo"]["PragmaGetDensityMatrix"] = False initial_statevector = [] for op in circuit: if "PragmaSetStateVector" in op.tags(): initial_statevector = op.statevector() elif "PragmaRepeatedMeasurement" in op.tags(): if "PragmaRepeatedMeasurement" not in circuit_info["MeasurementInfo"]: circuit_info["MeasurementInfo"]["PragmaRepeatedMeasurement"] = [] circuit_info["MeasurementInfo"]["PragmaRepeatedMeasurement"].append( (op.readout(), op.number_measurements(), op.qubit_mapping()) ) filtered_circuit += op elif "MeasureQubit" in op.tags(): if "MeasureQubit" not in circuit_info["MeasurementInfo"]: circuit_info["MeasurementInfo"]["MeasureQubit"] = [] circuit_info["MeasurementInfo"]["MeasureQubit"].append( (op.qubit(), op.readout(), op.readout_index()) ) filtered_circuit += op elif "PragmaSetNumberOfMeasurements" in op.tags(): if "PragmaSetNumberOfMeasurements" not in circuit_info["SimulationInfo"]: circuit_info["SimulationInfo"]["PragmaSetNumberOfMeasurements"] = [] circuit_info["SimulationInfo"]["PragmaSetNumberOfMeasurements"].append( (op.readout(), op.number_measurements()) ) elif "PragmaGetStateVector" in op.tags(): circuit_info["SimulationInfo"]["PragmaGetStateVector"] = True elif "PragmaGetDensityMatrix" in op.tags(): circuit_info["SimulationInfo"]["PragmaGetDensityMatrix"] = True elif "PragmaLoop" in op.tags(): if op.repetitions().is_float: for _ in range(int(op.repetitions().float())): filtered_circuit += op.circuit() else: raise ValueError("A symbolic PragmaLoop operation is not supported.") elif "PragmaSleep" in op.tags() or "RotateXY" in op.tags(): to_fix = True filtered_circuit += op else: filtered_circuit += op # qoqo_qasm call qasm_backend = QasmBackend(qubit_register_name=qubit_register_name) input_qasm_str = qasm_backend.circuit_to_qasm_str(filtered_circuit) # QASM -> Qiskit transformation return_circuit = QuantumCircuit() from_qasm_circuit = QuantumCircuit.from_qasm_str(input_qasm_str) # Fixing custom gates qiskit translation if to_fix: from_qasm_circuit = _custom_gates_fix(from_qasm_circuit) # Handling PragmaSetStateVector if len(initial_statevector) != 0: qregs = [] for qreg in from_qasm_circuit.qregs: qregs.append(QuantumRegister(qreg.size, qreg.name)) cregs = [] for creg in from_qasm_circuit.cregs: cregs.append(ClassicalRegister(creg.size, creg.name)) regs = qregs + cregs initial_circuit = QuantumCircuit(*regs) initial_circuit.initialize(initial_statevector) return_circuit = initial_circuit.compose(from_qasm_circuit) else: return_circuit = from_qasm_circuit return (return_circuit, circuit_info)
def _custom_gates_fix(from_qasm_circuit: QuantumCircuit) -> QuantumCircuit: """Transforms the custom gates imported by qiskit via QASM to correct qiskit Instructions. In case of incompatibilities, this step allows to directly keep the already transformed QuantumCircuit and modify the Instruction references imported via QASM. Args: from_qasm_circuit (QuantumCircuit): the qiskit QuantumCircuit to modify. Returns: QuantumCircuit: the modified qiskit QuantumCircuit. """ out_circuit = from_qasm_circuit.copy_empty_like() for inst, qargs, cargs in from_qasm_circuit.data: if inst.name == "pragmasleep": out_circuit.delay(inst.params[0], qargs[0], unit="s") elif inst.name == "rxy": out_circuit.r(inst.params[0], inst.params[1], qargs[0]) else: out_circuit.append(inst, qargs, cargs) return out_circuit