Source code for qiskit_quimb.gate

# (C) Copyright IBM 2024.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
from __future__ import annotations

from collections.abc import Iterator, Sequence
from typing import Any, Callable

import quimb.tensor
from qiskit.circuit import Instruction, QuantumCircuit

_gate_func: dict[
    str,
    Callable[[Instruction, Sequence[int], dict[str, Any]], quimb.tensor.Gate | None],
] = {}

SUPPORTED_GATES = _gate_func.keys()


def _register_gate_func(name: str):
    def g(f):
        _gate_func[name] = f
        return f

    return g


@_register_gate_func("barrier")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return None


@_register_gate_func("ccx")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("CCX", params=[], qubits=qubits, **kwargs)


@_register_gate_func("ccz")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("CCZ", params=[], qubits=qubits, **kwargs)


@_register_gate_func("cp")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    (theta,) = op.params
    return quimb.tensor.Gate("CPHASE", params=[theta], qubits=qubits, **kwargs)


@_register_gate_func("cx")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("CX", params=[], qubits=qubits, **kwargs)


@_register_gate_func("cy")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("CY", params=[], qubits=qubits, **kwargs)


@_register_gate_func("cz")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("CZ", params=[], qubits=qubits, **kwargs)


@_register_gate_func("global_phase")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return None


@_register_gate_func("h")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("H", params=[], qubits=qubits, **kwargs)


@_register_gate_func("id")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("IDEN", params=[], qubits=qubits, **kwargs)


@_register_gate_func("iswap")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("ISWAP", params=[], qubits=qubits, **kwargs)


@_register_gate_func("measure")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    raise ValueError(
        "Encountered a measurement gate, which is not allowed. "
        "Remove the measurements from your circuit and try again."
    )


@_register_gate_func("p")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    (theta,) = op.params
    return quimb.tensor.Gate("PHASE", params=[theta], qubits=qubits, **kwargs)


@_register_gate_func("rx")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    (theta,) = op.params
    return quimb.tensor.Gate("RX", params=[theta], qubits=qubits, **kwargs)


@_register_gate_func("rxx")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    (theta,) = op.params
    return quimb.tensor.Gate("RXX", params=[theta], qubits=qubits, **kwargs)


@_register_gate_func("ry")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    (theta,) = op.params
    return quimb.tensor.Gate("RY", params=[theta], qubits=qubits, **kwargs)


@_register_gate_func("ryy")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    (theta,) = op.params
    return quimb.tensor.Gate("RYY", params=[theta], qubits=qubits, **kwargs)


@_register_gate_func("rz")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    (theta,) = op.params
    return quimb.tensor.Gate("RZ", params=[theta], qubits=qubits, **kwargs)


@_register_gate_func("rzz")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    (theta,) = op.params
    return quimb.tensor.Gate("RZZ", params=[theta], qubits=qubits, **kwargs)


@_register_gate_func("s")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("S", params=[], qubits=qubits, **kwargs)


@_register_gate_func("sdg")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("SDG", params=[], qubits=qubits, **kwargs)


@_register_gate_func("sx")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("SX", params=[], qubits=qubits, **kwargs)


@_register_gate_func("sxdg")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("SXDG", params=[], qubits=qubits, **kwargs)


@_register_gate_func("swap")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("SWAP", params=[], qubits=qubits, **kwargs)


@_register_gate_func("t")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("T", params=[], qubits=qubits, **kwargs)


@_register_gate_func("tdg")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("TDG", params=[], qubits=qubits, **kwargs)


@_register_gate_func("u1")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    (theta,) = op.params
    return quimb.tensor.Gate("U1", params=[theta], qubits=qubits, **kwargs)


@_register_gate_func("u2")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    (phi, lam) = op.params
    return quimb.tensor.Gate("U2", params=[phi, lam], qubits=qubits, **kwargs)


@_register_gate_func("u3")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    (theta, phi, lam) = op.params
    return quimb.tensor.Gate("U3", params=[theta, phi, lam], qubits=qubits, **kwargs)


@_register_gate_func("x")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("X", params=[], qubits=qubits, **kwargs)


@_register_gate_func("xx_minus_yy")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    theta, beta = op.params
    return quimb.tensor.Gate("XXMINUSYY", params=[theta, beta], qubits=qubits, **kwargs)


@_register_gate_func("xx_plus_yy")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    theta, beta = op.params
    return quimb.tensor.Gate("XXPLUSYY", params=[theta, beta], qubits=qubits, **kwargs)


@_register_gate_func("y")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("Y", params=[], qubits=qubits, **kwargs)


@_register_gate_func("z")
def _(op: Instruction, qubits: Sequence[int], kwargs: dict[str, Any]):
    return quimb.tensor.Gate("Z", params=[], qubits=qubits, **kwargs)


[docs] def quimb_gate( op: Instruction, qubits: Sequence[int], **kwargs ) -> quimb.tensor.Gate | None: """Convert a Qiskit gate to a quimb gate, or ``None`` in case of a barrier.""" try: func = _gate_func[op.name] except KeyError: raise ValueError(f"Unsupported gate: {op.name}.") from None else: return func(op, qubits, kwargs)
[docs] def quimb_gates(circuit: QuantumCircuit) -> list[quimb.tensor.Gate]: """Convert a Qiskit circuit to a list of quimb gates.""" gates = [] for instruction in circuit.data: op = instruction.operation qubits = [circuit.find_bit(qubit).index for qubit in instruction.qubits] for gate in _gen_quimb_gates(op, qubits): gates.append(gate) return gates
def _gen_quimb_gates( op: Instruction, qubits: Sequence[int], **kwargs ) -> Iterator[quimb.tensor.Gate]: """Convert a Qiskit gate to quimb gates.""" name = op.name if name in ["barrier", "global_phase"]: pass else: yield quimb_gate(op, qubits, **kwargs)