microsoft/qdk
Publicmirrored from https://github.com/microsoft/qdkAvailable
source/pip/qsharp/interop/qiskit/backends/qirtarget.py
191lines · modecode
| 1 | # Copyright (c) Microsoft Corporation. |
| 2 | # Licensed under the MIT License. |
| 3 | |
| 4 | import logging |
| 5 | from typing import Union |
| 6 | |
| 7 | from qiskit.circuit import ( |
| 8 | Barrier, |
| 9 | Delay, |
| 10 | Measure, |
| 11 | Parameter, |
| 12 | Reset, |
| 13 | Store, |
| 14 | ) |
| 15 | from qiskit.circuit.controlflow import ( |
| 16 | ControlFlowOp, |
| 17 | ForLoopOp, |
| 18 | IfElseOp, |
| 19 | SwitchCaseOp, |
| 20 | WhileLoopOp, |
| 21 | ) |
| 22 | from qiskit.circuit.library.standard_gates import ( |
| 23 | CHGate, |
| 24 | CCXGate, |
| 25 | CXGate, |
| 26 | CYGate, |
| 27 | CZGate, |
| 28 | CRXGate, |
| 29 | CRYGate, |
| 30 | CRZGate, |
| 31 | RXGate, |
| 32 | RXXGate, |
| 33 | RYGate, |
| 34 | RYYGate, |
| 35 | RZGate, |
| 36 | RZZGate, |
| 37 | HGate, |
| 38 | SGate, |
| 39 | SdgGate, |
| 40 | SXGate, |
| 41 | SwapGate, |
| 42 | TGate, |
| 43 | TdgGate, |
| 44 | XGate, |
| 45 | YGate, |
| 46 | ZGate, |
| 47 | IGate, |
| 48 | ) |
| 49 | |
| 50 | from qiskit.transpiler.target import Target |
| 51 | from .... import TargetProfile |
| 52 | |
| 53 | logger = logging.getLogger(__name__) |
| 54 | |
| 55 | |
| 56 | class QirTarget: |
| 57 | """Factory for QIR-compatible Qiskit ``Target`` instances.""" |
| 58 | |
| 59 | def __init__( |
| 60 | self, |
| 61 | num_qubits=None, |
| 62 | target_profile=TargetProfile.Base, |
| 63 | supports_barrier=False, |
| 64 | supports_delay=False, |
| 65 | ) -> None: |
| 66 | logger.warning( |
| 67 | "QirTarget should not be instantiated directly. Use the 'build_target' class method" |
| 68 | + " instead. This will be enforced in a future release. You can replace" |
| 69 | + " 'QirTarget(...)' with 'QirTarget.build_target(...)'." |
| 70 | ) |
| 71 | self._target = self.build_target( |
| 72 | num_qubits=num_qubits, |
| 73 | target_profile=target_profile, |
| 74 | supports_barrier=supports_barrier, |
| 75 | supports_delay=supports_delay, |
| 76 | ) |
| 77 | |
| 78 | def __getattr__(self, item): |
| 79 | """ |
| 80 | Delegate attribute access to the underlying _target object. |
| 81 | |
| 82 | This method is called when an attribute is not found in the current instance. |
| 83 | It forwards the attribute lookup to the internal _target object, effectively |
| 84 | making this class act as a proxy or wrapper around the target. |
| 85 | |
| 86 | :param item: The name of the attribute being accessed. |
| 87 | :return: The value of the requested attribute from the ``_target`` object. |
| 88 | :raises AttributeError: If the requested item is ``"_target"`` or if the attribute |
| 89 | does not exist on the ``_target`` object. |
| 90 | """ |
| 91 | if item == "_target": |
| 92 | raise AttributeError(item) |
| 93 | return getattr(self._target, item) |
| 94 | |
| 95 | def to_target(self) -> Target: |
| 96 | """Return the underlying Qiskit Target instance.""" |
| 97 | return self._target |
| 98 | |
| 99 | @classmethod |
| 100 | def build_target( |
| 101 | cls, |
| 102 | num_qubits: Union[int, None] = None, |
| 103 | target_profile=TargetProfile.Base, |
| 104 | supports_barrier=False, |
| 105 | supports_delay=False, |
| 106 | ) -> Target: |
| 107 | """ |
| 108 | Create a Qiskit Target object with quantum gates and operations for QIR compilation. |
| 109 | |
| 110 | This class method creates a Target instance that defines the available quantum |
| 111 | operations and gates that can be used when compiling Q#/OpenQASM code to QIR (Quantum |
| 112 | Intermediate Representation) format. |
| 113 | |
| 114 | :param num_qubits: The number of qubits for the target. |
| 115 | If ``None``, the target will support any number of qubits. Defaults to ``None``. |
| 116 | :param target_profile: The target profile that determines which control flow operations |
| 117 | are supported. If not ``TargetProfile.Base``, adds control flow operations like |
| 118 | ``if_else``, ``switch_case``, and ``while_loop``. Defaults to ``TargetProfile.Base``. |
| 119 | :param supports_barrier: Whether to include barrier operations in the target. |
| 120 | Defaults to ``False``. |
| 121 | :param supports_delay: Whether to include delay operations in the target. |
| 122 | Defaults to ``False``. |
| 123 | :return: A Qiskit ``Target`` object configured with quantum gates and operations. |
| 124 | """ |
| 125 | |
| 126 | target = Target(num_qubits=num_qubits) |
| 127 | |
| 128 | if target_profile != TargetProfile.Base: |
| 129 | target.add_instruction(ControlFlowOp, name="control_flow") |
| 130 | target.add_instruction(IfElseOp, name="if_else") |
| 131 | target.add_instruction(SwitchCaseOp, name="switch_case") |
| 132 | target.add_instruction(WhileLoopOp, name="while_loop") |
| 133 | |
| 134 | # We don't currently support break or continue statements in Q#, |
| 135 | # so we don't include them yet. |
| 136 | # target.add_instruction(BreakLoopOp, name="break") |
| 137 | # target.add_instruction(ContinueLoopOp, name="continue") |
| 138 | |
| 139 | target.add_instruction(Store, name="store") |
| 140 | |
| 141 | if supports_barrier: |
| 142 | target.add_instruction(Barrier, name="barrier") |
| 143 | if supports_delay: |
| 144 | target.add_instruction(Delay, name="delay") |
| 145 | |
| 146 | # For loops should be fully deterministic in Qiskit/QASM. |
| 147 | target.add_instruction(ForLoopOp, name="for_loop") |
| 148 | target.add_instruction(Measure, name="measure") |
| 149 | |
| 150 | # While reset is technically not supported in base profile, the |
| 151 | # compiler can use decompositions to implement workarounds. |
| 152 | target.add_instruction(Reset, name="reset") |
| 153 | |
| 154 | target.add_instruction(CCXGate, name="ccx") |
| 155 | target.add_instruction(CXGate, name="cx") |
| 156 | target.add_instruction(CYGate, name="cy") |
| 157 | target.add_instruction(CZGate, name="cz") |
| 158 | |
| 159 | target.add_instruction(RXGate(Parameter("theta")), name="rx") |
| 160 | target.add_instruction(RXXGate(Parameter("theta")), name="rxx") |
| 161 | target.add_instruction(CRXGate(Parameter("theta")), name="crx") |
| 162 | |
| 163 | target.add_instruction(RYGate(Parameter("theta")), name="ry") |
| 164 | target.add_instruction(RYYGate(Parameter("theta")), name="ryy") |
| 165 | target.add_instruction(CRYGate(Parameter("theta")), name="cry") |
| 166 | |
| 167 | target.add_instruction(RZGate(Parameter("theta")), name="rz") |
| 168 | target.add_instruction(RZZGate(Parameter("theta")), name="rzz") |
| 169 | target.add_instruction(CRZGate(Parameter("theta")), name="crz") |
| 170 | |
| 171 | target.add_instruction(HGate, name="h") |
| 172 | |
| 173 | target.add_instruction(SGate, name="s") |
| 174 | target.add_instruction(SdgGate, name="sdg") |
| 175 | |
| 176 | target.add_instruction(SXGate, name="sx") |
| 177 | |
| 178 | target.add_instruction(SwapGate, name="swap") |
| 179 | |
| 180 | target.add_instruction(TGate, name="t") |
| 181 | target.add_instruction(TdgGate, name="tdg") |
| 182 | |
| 183 | target.add_instruction(XGate, name="x") |
| 184 | target.add_instruction(YGate, name="y") |
| 185 | target.add_instruction(ZGate, name="z") |
| 186 | |
| 187 | target.add_instruction(IGate, name="id") |
| 188 | |
| 189 | target.add_instruction(CHGate, name="ch") |
| 190 | |
| 191 | return target |
| 192 | |