Source code for mqt.bench.targets.gatesets.ionq

# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
# All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Licensed under the MIT License

# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2018.
#
# 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.

# Copyright 2024 IonQ, Inc. (www.ionq.com)
#
# 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.


"""Handles the available native gatesets for IonQ."""

from __future__ import annotations

from typing import TYPE_CHECKING

import numpy as np
from qiskit import QuantumCircuit, QuantumRegister
from qiskit.circuit import Gate, Parameter
from qiskit.circuit.library import CXGate, UGate

from ._registry import register_gateset

if TYPE_CHECKING:
    from qiskit.circuit import EquivalenceLibrary
    from qiskit.circuit.parameterexpression import ParameterValueType


[docs] @register_gateset("ionq_forte") def get_ionq_forte_gateset() -> list[str]: """Returns the basis gates of the IonQ Forte gateset.""" return ["rz", "gpi", "gpi2", "zz", "measure"]
[docs] @register_gateset("ionq_aria") def get_ionq_aria_gateset() -> list[str]: """Returns the basis gates of the IonQ Aria gateset.""" return ["rz", "gpi", "gpi2", "ms", "measure"]
[docs] class GPIGate(Gate): r"""Single-qubit GPI gate. **Circuit symbol:** .. parsed-literal:: ┌───────┐ q_0: ┤ GPI(φ)├ └───────┘ **Matrix Representation:**. .. math:: GPI(\phi) = \begin{pmatrix} 0 & e^{-i*2*\pi*\phi} \\ e^{i*2*\pi*\phi} & 0 \end{pmatrix} """ def __init__(self, phi: ParameterValueType, label: str | None = None) -> None: """Create new GPI gate.""" super().__init__("gpi", 1, [phi], label=label) def _define(self) -> None: """Define the GPI gate.""" phi = self.params[0] q = QuantumRegister(1, "q") qc = QuantumCircuit(q) qc.x(0) qc.rz(4 * phi * np.pi, 0) self.definition = qc
[docs] class GPI2Gate(Gate): r"""Single-qubit GPI2 gate. **Circuit symbol:** .. parsed-literal:: ┌───────┐ q_0: ┤GPI2(φ)├ └───────┘ **Matrix Representation:**. .. math:: GPI2(\phi) = \frac{1}{\sqrt{2}} \begin{pmatrix} 1 & -i*e^{-i*2*\pi*\phi} \\ -i*e^{i*2*\pi*\phi} & 1 \end{pmatrix} """ def __init__(self, phi: ParameterValueType, label: str | None = None) -> None: """Create new GPI2 gate.""" super().__init__("gpi2", 1, [phi], label=label) def _define(self) -> None: """Define the GPI2 gate.""" phi = self.params[0] q = QuantumRegister(1, "q") qc = QuantumCircuit(q) qc.rz(-2 * phi * np.pi, 0) qc.rx(np.pi / 2, 0) qc.rz(2 * phi * np.pi, 0) self.definition = qc
[docs] class MSGate(Gate): r"""Entangling 2-Qubit MS gate. **Circuit symbol:** .. parsed-literal:: _______ q_0: ┤ ├- \|MS(ϴ,0)\| q_1: ┤ ├- └───────┘ **Matrix representation:**. .. math:: MS(\phi_0, \phi_1, \theta) = \begin{pmatrix} cos(\theta*\pi) & 0 & 0 & -i*e^{-i*2*\pi(\phi_0+\phi_1)}*sin(\theta*\pi) \\ 0 & cos(\theta*\pi) & -i*e^{i*2*\pi(\phi_0-\phi_1)}*sin(\theta*\pi) & 0 \\ 0 & -i*e^{-i*2*\pi(\phi_0-\phi_1)}*sin(\theta*\pi) & cos(\theta*\pi) & 0 \\ -i*e^{i*2*\pi(\phi_0+\phi_1)}*sin(\theta*\pi) & 0 & 0 & cos(\theta*\pi) \end{pmatrix} """ def __init__( self, phi0: ParameterValueType, phi1: ParameterValueType, theta: ParameterValueType | None = 0.25, label: str | None = None, ) -> None: """Create new MS gate.""" super().__init__( "ms", 2, [phi0, phi1, theta], label=label, ) def _define(self) -> None: """Define the MS gate.""" phi0 = self.params[0] phi1 = self.params[1] theta = self.params[2] q = QuantumRegister(2, "q") alpha = phi0 + phi1 beta = phi0 - phi1 qc = QuantumCircuit(q) qc.cx(q[1], q[0]) qc.x(q[0]) qc.cu( 2 * theta * np.pi, 2 * alpha * np.pi - np.pi / 2, np.pi / 2 - 2 * alpha * np.pi, 0, # gamma control_qubit=q[0], target_qubit=q[1], ) qc.x(q[0]) qc.cu( 2 * theta * np.pi, -2 * beta * np.pi - np.pi / 2, np.pi / 2 + 2 * beta * np.pi, 0, # gamma control_qubit=q[0], target_qubit=q[1], ) qc.cx(q[1], q[0]) self.definition = qc
[docs] class ZZGate(Gate): r"""Two-qubit ZZ-rotation gate. **Circuit Symbol:** .. parsed-literal:: q_0: ───■──── │zz(θ) q_1: ───■──── **Matrix Representation:**. .. math:: ZZ(\theta) = \begin{pmatrix} e^{-i \theta*\pi} & 0 & 0 & 0 \\ 0 & e^{i \theta*\pi} & 0 & 0 \\ 0 & 0 & e^{i \theta*\pi} & 0 \\ 0 & 0 & 0 & e^{-i \theta\*\pi} \end{pmatrix} """ def __init__(self, theta: ParameterValueType, label: str | None = None) -> None: """Create new ZZ gate.""" super().__init__("zz", 2, [theta], label=label) def _define(self) -> None: """Define the ZZ gate.""" theta = self.params[0] q = QuantumRegister(2, "q") qc = QuantumCircuit(q) qc.rzz(2 * np.pi * theta, 0, 1) self.definition = qc
[docs] def u_gate_equivalence(sel: EquivalenceLibrary) -> None: """Add U gate equivalence to the SessionEquivalenceLibrary.""" q = QuantumRegister(1, "q") theta_param = Parameter("theta_param") phi_param = Parameter("phi_param") lambda_param = Parameter("lambda_param") u_gate = QuantumCircuit(q) u_gate.append(GPI2Gate(0.5 - lambda_param / (2 * np.pi)), [0]) u_gate.append( GPIGate(theta_param / (4 * np.pi) + phi_param / (4 * np.pi) - lambda_param / (4 * np.pi)), [0], ) u_gate.append(GPI2Gate(0.5 + phi_param / (2 * np.pi)), [0]) sel.add_equivalence(UGate(theta_param, phi_param, lambda_param), u_gate)
[docs] def cx_via_ms_equivalence(sel: EquivalenceLibrary) -> None: """Add CX gate equivalence to the SessionEquivalenceLibrary for both native two-qubit gates.""" q = QuantumRegister(2, "q") cx_gate = QuantumCircuit(q) cx_gate.append(GPI2Gate(1 / 4), [0]) cx_gate.append(MSGate(0, 0, 0.25), [0, 1]) cx_gate.append(GPI2Gate(1 / 2), [0]) cx_gate.append(GPI2Gate(1 / 2), [1]) cx_gate.append(GPI2Gate(-1 / 4), [0]) sel.add_equivalence(CXGate(), cx_gate)
[docs] def cx_via_zz_equivalence(sel: EquivalenceLibrary) -> None: """Add equivalence CX ≡ H-ZZ(pi/4)-H.""" q = QuantumRegister(2, "q") cx_equiv = QuantumCircuit(q) cx_equiv.h(1) cx_equiv.append(ZZGate(0.25), [0, 1]) # pi/4 cx_equiv.h(1) sel.add_equivalence(CXGate(), cx_equiv)
[docs] def add_equivalences(sel: EquivalenceLibrary) -> None: """Add IonQ gate equivalences to the SessionEquivalenceLibrary.""" u_gate_equivalence(sel) cx_via_ms_equivalence(sel) cx_via_zz_equivalence(sel)