{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "24576595",
      "metadata": {},
      "source": [
        "---\n",
        "title: Quantum kernels with fractional gates\n",
        "description: Use fractional gates, parameterized gates that directly execute arbitrary-angle rotations, to reduce the depth and duration of quantum kernel circuits.\n",
        "---\n",
        "\n",
        "# Quantum kernels with fractional gates\n",
        "\n",
        "*Usage estimate: under 30 seconds on a Heron r2 processor (NOTE: This is an estimate only. Your runtime may vary.)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "983da41e",
      "metadata": {},
      "source": [
        "## Learning outcomes\n",
        "\n",
        "* What fractional gates are and how they reduce circuit depth and duration on IBM® QPUs\n",
        "* The constraints associated with using fractional gates (in particular, the RZZ angle range)\n",
        "* How to construct a quantum kernel workflow that uses fractional gates with IBM Quantum Compute Service\n",
        "* How to compare hardware-execution metrics (depth, duration, non-local gate count, fidelity) with and without fractional gates\n",
        "* How to use only fractional RX gates while keeping the standard Qiskit patterns workflow\n",
        "\n",
        "## Prerequisites\n",
        "\n",
        "* The [Qiskit patterns](/docs/guides/intro-to-patterns) workflow\n",
        "* The [Fractional gates](/docs/guides/fractional-gates) guide\n",
        "* The [Quantum kernel training](/docs/tutorials/quantum-kernel-training) tutorial and the [Quantum kernels](/learning/courses/quantum-machine-learning/quantum-kernel-methods) lesson of the Quantum machine learning course\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "155eab76",
      "metadata": {},
      "source": [
        "## Background\n",
        "\n",
        "### Fractional gates on IBM QPUs\n",
        "\n",
        "Fractional gates are parameterized quantum gates that enable direct execution of arbitrary-angle rotations (within specific bounds),\n",
        "eliminating the need to decompose them into multiple basis gates.\n",
        "By leveraging the native interactions between physical qubits, you can implement certain unitaries more efficiently on hardware.\n",
        "\n",
        "IBM Quantum® Heron QPUs support the following fractional gates:\n",
        "\n",
        "* $R_{ZZ}(\\theta)$ for $0 < \\theta < \\pi / 2$\n",
        "* $R_X(\\theta)$ for any real value $\\theta$\n",
        "\n",
        "These gates can significantly reduce both the depth and duration of quantum circuits.\n",
        "They are particularly advantageous in applications that rely heavily on $R_{ZZ}$ and $R_X$,\n",
        "such as Hamiltonian simulation, the Quantum Approximate Optimization Algorithm (QAOA), and quantum kernel methods.\n",
        "In this tutorial, we focus on the quantum kernel as a practical example.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fe5675f3",
      "metadata": {},
      "source": [
        "### Limitations\n",
        "\n",
        "Fractional gates are currently an experimental feature and come with a few constraints:\n",
        "\n",
        "* $R_{ZZ}$ is limited to angles in the range $0 < \\theta < \\pi / 2$.\n",
        "* Using fractional gates is not supported for [dynamic circuits](/docs/guides/classical-feedforward-and-control-flow), [Pauli twirling](/docs/guides/error-mitigation-and-suppression-techniques#pauli-twirling), [probabilistic error cancellation](/docs/guides/error-mitigation-and-suppression-techniques#probabilistic-error-cancellation-pec) (PEC), and [zero-noise extrapolation](/docs/guides/error-mitigation-and-suppression-techniques#zero-noise-extrapolation-zne) (ZNE) (using [probabilistic error amplification](/docs/guides/error-mitigation-and-suppression-techniques#probabilistic-error-amplification-pea) (PEA)).\n",
        "\n",
        "Fractional gates require a different workflow compared to the standard approach.\n",
        "This tutorial explains how to work with fractional gates through a practical application.\n",
        "\n",
        "See the following for more details on fractional gates.\n",
        "\n",
        "* [Fractional gates](/docs/guides/fractional-gates)\n",
        "* [When *not* to use fractional gates](/docs/guides/fractional-gates#when-not-to-use)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a4bdab87",
      "metadata": {},
      "source": [
        "### Workflow approaches for the RZZ angle constraint\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "db213506",
      "metadata": {},
      "source": [
        "The workflow for using fractional gates generally follows the [Qiskit patterns](/docs/guides/intro-to-patterns) workflow.\n",
        "The key difference is that all RZZ angles must satisfy the constraint $0 < \\theta \\leq \\pi/2$.\n",
        "There are two approaches to ensure this condition is met, as we discuss below. We recommend the second approach, and in this tutorial, we demonstrate it through an example inspired by the quantum kernel method.\n",
        "To better understand where quantum kernels are likely to be useful, we recommend reading [Liu, Arunachalam & Temme (2021)](https://www.nature.com/articles/s41567-021-01287-z).\n",
        "\n",
        "You can also work through the [Quantum kernel training](/docs/tutorials/quantum-kernel-training) tutorial and the [Quantum kernels](/learning/courses/quantum-machine-learning/quantum-kernel-methods) lesson in the Quantum machine learning course on IBM Quantum® Learning.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5797ed7e",
      "metadata": {},
      "source": [
        "#### 1. Generate parameter values that satisfy the RZZ angle constraint\n",
        "\n",
        "If you are confident that all RZZ angles fall within the valid range, you can follow the standard Qiskit patterns workflow.\n",
        "In this case, you simply submit the parameter values as part of a PUB. The workflow proceeds as follows.\n",
        "\n",
        "```python\n",
        "pm = generate_preset_pass_manager(backend=backend, ...)\n",
        "t_circuit = pm.run(circuit)\n",
        "t_observable = observable.apply_layout(t_circuit.layout)\n",
        "sampler.run([(t_circuit, parameter_values)])\n",
        "estimator.run([(t_circuit, t_observable, parameter_values)])\n",
        "```\n",
        "\n",
        "If you attempt to submit a PUB that includes an RZZ gate with an angle outside the valid range, you will encounter an error message such as:\n",
        "\n",
        "```\n",
        "'The instruction rzz is supported only for angles in the range [0, pi/2], but an angle (20.0) outside of this range has been requested; via parameter value(s) γ[0]=10.0, substituted in parameter expression 2.0*γ[0].'\n",
        "```\n",
        "\n",
        "To avoid this error, use the second approach described below.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d3e00f37",
      "metadata": {},
      "source": [
        "#### 2. Assign parameter values to circuits before transpilation\n",
        "\n",
        "The `qiskit-ibm-runtime` package provides a specialized transpiler pass called [`FoldRzzAngle`](/docs/api/qiskit-ibm-runtime/transpiler-passes-fold-rzz-angle).\n",
        "This pass transforms quantum circuits so that all RZZ angles comply with the RZZ angle constraint.\n",
        "If you provide the backend to `generate_preset_pass_manager` or `transpile`, Qiskit automatically applies `FoldRzzAngle` to the quantum circuits.\n",
        "This approach requires you to assign parameter values to quantum circuits before transpilation.\n",
        "The workflow proceeds as follows.\n",
        "\n",
        "```python\n",
        "pm = generate_preset_pass_manager(backend=backend, ...)\n",
        "b_circuit = circuit.assign_parameters(parameter_values)\n",
        "t_circuit = pm.run(b_circuit)\n",
        "t_observable = observable.apply_layout(t_circuit.layout)\n",
        "sampler.run([(t_circuit,)])\n",
        "estimator.run([(t_circuit, t_observable)])\n",
        "```\n",
        "\n",
        "Note that this workflow incurs a higher computational cost than the first approach, as it involves assigning parameter values to quantum circuits and storing the parameter-bound circuits locally.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b7cb1bd2",
      "metadata": {},
      "source": [
        "<Admonition type=\"caution\">\n",
        "  **Take note of a known issue in `qiskit-ibm-runtime` v0.47.0** where RZZ gates with invalid angles might remain in the circuits even after transpilation in certain scenarios.\n",
        "\n",
        "  See [qiskit-ibm-runtime#2441](https://github.com/Qiskit/qiskit-ibm-runtime/issues/2441) to track progress on this issue.\n",
        "  We recommend the following workaround until it is resolved.\n",
        "\n",
        "  ```python\n",
        "  pm = generate_preset_pass_manager(backend=backend, ...)\n",
        "  pm.post_optimization = PassManager(\n",
        "      [\n",
        "          FoldRzzAngle(),\n",
        "          Optimize1qGatesDecomposition(target=backend.target),\n",
        "          RemoveIdentityEquivalent(target=backend.target),\n",
        "      ]\n",
        "  )\n",
        "  ... = pm.run(...)\n",
        "  ```\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "aaa153e7",
      "metadata": {},
      "source": [
        "## Requirements\n",
        "\n",
        "Before starting this tutorial, be sure you have the following installed:\n",
        "\n",
        "* Qiskit SDK v2.0 or later, with [visualization](/docs/api/qiskit/visualization) support\n",
        "* Qiskit Runtime v0.41 or later (`pip install qiskit-ibm-runtime`)\n",
        "* Qiskit Aer v0.17 or later (`pip install qiskit-aer`)\n",
        "* Qiskit Basis Constructor (`pip install qiskit_basis_constructor`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5f43ce5d",
      "metadata": {},
      "source": [
        "## Setup\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "a6a15694",
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "from qiskit import QuantumCircuit, generate_preset_pass_manager\n",
        "from qiskit.circuit import ParameterVector\n",
        "from qiskit.circuit.library import UGate, n_local, unitary_overlap\n",
        "from qiskit.transpiler import Target, PassManager\n",
        "from qiskit.transpiler.passes import (\n",
        "    Optimize1qGatesDecomposition,\n",
        "    RemoveIdentityEquivalent,\n",
        ")\n",
        "from qiskit_aer.primitives import SamplerV2 as AerSampler\n",
        "from qiskit_basis_constructor import DEFAULT_EQUIVALENCE_LIBRARY\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2\n",
        "from qiskit_ibm_runtime.transpiler.passes import FoldRzzAngle"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3e94382d",
      "metadata": {},
      "source": [
        "### Enable fractional gates and check basis gates\n",
        "\n",
        "To use fractional gates, you can obtain a backend that supports them by setting the `use_fractional_gates=True` option.\n",
        "If the backend supports fractional gates, you will see `rzz` and `rx` listed among its basis gates.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "fd577102",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Backend: ibm_marrakesh\n",
            "No fractional gates: ['cz', 'id', 'rz', 'sx', 'x']\n",
            "With fractional gates: ['cz', 'id', 'rx', 'rz', 'rzz', 'sx', 'x']\n"
          ]
        }
      ],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=133\n",
        ")  # backend should be a heron device or later\n",
        "backend_name = backend.name\n",
        "backend_c = service.backend(backend_name)  # w/o fractional gates\n",
        "backend_f = service.backend(\n",
        "    backend_name, use_fractional_gates=True\n",
        ")  # w/ fractional gates\n",
        "print(f\"Backend: {backend_name}\")\n",
        "print(f\"No fractional gates: {backend_c.basis_gates}\")\n",
        "print(f\"With fractional gates: {backend_f.basis_gates}\")\n",
        "if \"rzz\" not in backend_f.basis_gates:\n",
        "    print(f\"Backend {backend_name} does not support fractional gates\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3f11c5a3",
      "metadata": {},
      "source": [
        "## Small-scale simulator example\n",
        "\n",
        "In this section, we walk through the four steps of the [Qiskit patterns](/docs/guides/intro-to-patterns) workflow on a simulator, using the quantum kernel circuit as a practical example.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7bfd6a97",
      "metadata": {},
      "source": [
        "### Step 1: Map classical inputs to a quantum problem\n",
        "\n",
        "#### Quantum kernel circuit\n",
        "\n",
        "In this section, we explore the quantum kernel circuit using RZZ gates to introduce the workflow for fractional gates.\n",
        "\n",
        "We begin by constructing a quantum circuit to compute individual entries of the kernel matrix.\n",
        "This is done by combining ZZ feature map circuits with a unitary overlap.\n",
        "The kernel function takes vectors in the feature-mapped space and returns their inner product as an entry of the kernel matrix:\n",
        "$K(x, y) = \\langle \\Phi(x) | \\Phi(y) \\rangle,$\n",
        "where $|\\Phi(x)\\rangle$ represents the feature-mapped quantum state.\n",
        "\n",
        "We manually construct a ZZ feature map circuit using RZZ gates.\n",
        "Although Qiskit provides a built-in `zz_feature_map`, it does not currently support RZZ gates as of Qiskit v2.4.1 ([see issue](https://github.com/Qiskit/qiskit/issues/14469)).\n",
        "\n",
        "Next, we compute the kernel function for identical inputs - for example, $K(x, x) = 1$.\n",
        "On noisy quantum computers, this value may be less than 1 due to noise.\n",
        "A result closer to 1 indicates lower noise in the execution.\n",
        "In this tutorial, we refer to this value as the *fidelity*, defined as\n",
        "$\\text{fidelity} = K(x, x).$\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "e7d5b52a",
      "metadata": {},
      "outputs": [],
      "source": [
        "optimization_level = 2\n",
        "shots = 2000\n",
        "reps = 3\n",
        "rng = np.random.default_rng(seed=123)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "2e9ab33d",
      "metadata": {},
      "outputs": [],
      "source": [
        "def my_zz_feature_map(num_qubits: int, reps: int = 1) -> QuantumCircuit:\n",
        "    x = ParameterVector(\"x\", num_qubits * reps)\n",
        "    qc = QuantumCircuit(num_qubits)\n",
        "    qc.h(range(num_qubits))\n",
        "    for k in range(reps):\n",
        "        K = k * num_qubits\n",
        "        for i in range(num_qubits):\n",
        "            qc.rz(x[i + K], i)\n",
        "        pairs = [(i, i + 1) for i in range(num_qubits - 1)]\n",
        "        for i, j in pairs[0::2] + pairs[1::2]:\n",
        "            qc.rzz((np.pi - x[i + K]) * (np.pi - x[j + K]), i, j)\n",
        "    return qc\n",
        "\n",
        "\n",
        "def quantum_kernel(num_qubits: int, reps: int = 1) -> QuantumCircuit:\n",
        "    qc = my_zz_feature_map(num_qubits, reps=reps)\n",
        "    inner_product = unitary_overlap(qc, qc, \"x\", \"y\", insert_barrier=True)\n",
        "    inner_product.measure_all()\n",
        "    return inner_product\n",
        "\n",
        "\n",
        "def random_parameters(inner_product: QuantumCircuit) -> np.ndarray:\n",
        "    return np.tile(rng.random(inner_product.num_parameters // 2), 2)\n",
        "\n",
        "\n",
        "def fidelity(result) -> float:\n",
        "    ba = result.data.meas\n",
        "    return ba.get_int_counts().get(0, 0) / ba.num_shots"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f676ff81",
      "metadata": {},
      "source": [
        "Quantum kernel circuits and their corresponding parameter values are generated for systems with 4 to 40 qubits, and their fidelities are subsequently evaluated.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "24116973",
      "metadata": {},
      "outputs": [],
      "source": [
        "qubits = list(range(4, 12, 2))\n",
        "circuits = [quantum_kernel(i, reps=reps) for i in qubits]\n",
        "params = [random_parameters(circ) for circ in circuits]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "30a7c442",
      "metadata": {},
      "source": [
        "The four-qubit circuit is visualized below.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "b3d6341a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/b3d6341a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "circuits[0].draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "07f31cbe",
      "metadata": {},
      "source": [
        "In the standard Qiskit patterns workflow, parameter values are typically passed to the Sampler or Estimator primitive as part of a PUB.\n",
        "However, when using a backend that supports fractional gates, these parameter values must be explicitly assigned to the quantum circuit prior to transpilation.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "6c9c1977",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/6c9c1977-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "b_qc = [\n",
        "    circ.assign_parameters(param) for circ, param in zip(circuits, params)\n",
        "]\n",
        "b_qc[0].draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7513072b",
      "metadata": {},
      "source": [
        "### Step 2: Optimize problem for quantum hardware execution\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "804ba317",
      "metadata": {},
      "source": [
        "We then transpile the circuit using the pass manager following the standard Qiskit pattern.\n",
        "By providing a backend that supports fractional gates to `generate_preset_pass_manager`, a specialized pass called `FoldRzzAngle` is automatically included.\n",
        "This pass modifies the circuit to comply with the RZZ angle constraints.\n",
        "As a result, RZZ gates with negative values in the previous figure are transformed into positive values, and some additional X gates are added.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "6054bdea",
      "metadata": {},
      "outputs": [],
      "source": [
        "backend_f = service.backend(name=backend_name, use_fractional_gates=True)\n",
        "# pm_f includes `FoldRzzAngle` pass\n",
        "pm_f = generate_preset_pass_manager(\n",
        "    optimization_level=optimization_level, backend=backend_f\n",
        ")\n",
        "pm_f.post_optimization = PassManager(\n",
        "    [\n",
        "        FoldRzzAngle(),\n",
        "        Optimize1qGatesDecomposition(target=backend_f.target),\n",
        "        RemoveIdentityEquivalent(target=backend_f.target),\n",
        "    ]\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "a18e5c70",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OrderedDict({'rz': 35, 'rzz': 18, 'x': 13, 'rx': 9, 'measure': 4, 'barrier': 2})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/a18e5c70-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "t_qc_f = pm_f.run(b_qc)\n",
        "print(t_qc_f[0].count_ops())\n",
        "t_qc_f[0].draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a4cd07d1",
      "metadata": {},
      "source": [
        "To assess the impact of fractional gates, we evaluate the number of non-local gates (CZ and RZZ for this backend),\n",
        "along with circuit depths and durations, and compare these metrics to those from a standard workflow later.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "b5bcf9ad",
      "metadata": {},
      "outputs": [],
      "source": [
        "nnl_f = [qc.num_nonlocal_gates() for qc in t_qc_f]\n",
        "depth_f = [qc.depth() for qc in t_qc_f]\n",
        "duration_f = [\n",
        "    qc.estimate_duration(backend_f.target, unit=\"u\") for qc in t_qc_f\n",
        "]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "629406cc",
      "metadata": {},
      "source": [
        "### Step 3: Execute using Qiskit primitives\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "87926539",
      "metadata": {},
      "source": [
        "We run the transpiled circuit with the backend that supports fractional gates.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "a68acf11",
      "metadata": {},
      "outputs": [],
      "source": [
        "sampler_f = AerSampler.from_backend(backend_f)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "a703b939",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "085ce928-767e-4200-93bf-3905e5411cfe\n"
          ]
        }
      ],
      "source": [
        "job = sampler_f.run(t_qc_f, shots=shots)\n",
        "print(job.job_id())"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6c9fd10d",
      "metadata": {},
      "source": [
        "### Step 4: Post-process and return result in desired classical format\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7a865036",
      "metadata": {},
      "source": [
        "You can obtain the kernel function value $K(x, x)$ by measuring the probability of the all-zero bitstring `00...00` in the output.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "1f0d9c51",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[0.929, 0.882, 0.8645, 0.817]\n"
          ]
        }
      ],
      "source": [
        "result = job.result()\n",
        "fidelity_f = [fidelity(result=res) for res in result]\n",
        "print(fidelity_f)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a5bcd1a8",
      "metadata": {},
      "source": [
        "### Comparison of workflow and circuit without fractional gates\n",
        "\n",
        "In this section, we present the standard Qiskit patterns workflow using a backend that does not support fractional gates.\n",
        "By comparing the transpiled circuits, you will notice that the version using fractional gates (from the previous section) is more compact than the one without fractional gates.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "e97fd0d5",
      "metadata": {},
      "outputs": [],
      "source": [
        "# step 1: map classical inputs to quantum problem\n",
        "# `circuits` and `params` from the previous section are reused here"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "a10f2d95",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OrderedDict({'rz': 130, 'sx': 80, 'cz': 36, 'measure': 4, 'barrier': 2})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/a10f2d95-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 15,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# step 2: optimize circuits\n",
        "backend_c = service.backend(backend_name)  # w/o fractional gates\n",
        "pm_c = generate_preset_pass_manager(\n",
        "    optimization_level=optimization_level, backend=backend_c\n",
        ")\n",
        "t_qc_c = pm_c.run(circuits)\n",
        "print(t_qc_c[0].count_ops())\n",
        "t_qc_c[0].draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "bb3475df",
      "metadata": {},
      "outputs": [],
      "source": [
        "nnl_c = [qc.num_nonlocal_gates() for qc in t_qc_c]\n",
        "depth_c = [qc.depth() for qc in t_qc_c]\n",
        "duration_c = [\n",
        "    qc.estimate_duration(backend_c.target, unit=\"u\") for qc in t_qc_c\n",
        "]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "e8d307c0",
      "metadata": {},
      "outputs": [],
      "source": [
        "# step 3: execute\n",
        "sampler_c = AerSampler.from_backend(backend_c)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "id": "983dd26f",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "f2cca29d-7263-4976-9e51-13a91b75c3ae\n"
          ]
        }
      ],
      "source": [
        "job = sampler_c.run(pubs=zip(t_qc_c, params), shots=shots)\n",
        "print(job.job_id())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "a6a6fa77",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[0.8625, 0.7605, 0.702, 0.671]\n"
          ]
        }
      ],
      "source": [
        "# step 4: post-processing\n",
        "result = job.result()\n",
        "fidelity_c = [fidelity(res) for res in result]\n",
        "print(fidelity_c)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "765a7980",
      "metadata": {},
      "source": [
        "### Comparison of depths, durations, and fidelities\n",
        "\n",
        "In this section, we compare the number of non-local gates and the fidelities between circuits with and without fractional gates.\n",
        "This highlights the potential benefits of using fractional gates in terms of execution efficiency and quality.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "ef343a53",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x116af3cb0>"
            ]
          },
          "execution_count": 20,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/ef343a53-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, depth_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, depth_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"depth\")\n",
        "plt.title(\"Comparison of depths\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "98bb2cd0",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x11ea4f4d0>"
            ]
          },
          "execution_count": 21,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/98bb2cd0-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, duration_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, duration_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"duration (µs)\")\n",
        "plt.title(\"Comparison of durations\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "1383b242",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x1247fc440>"
            ]
          },
          "execution_count": 22,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/1383b242-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, nnl_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, nnl_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"number of non-local gates\")\n",
        "plt.title(\"Comparison of numbers of non-local gates\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "id": "8b4594f5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x120b792b0>"
            ]
          },
          "execution_count": 23,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/8b4594f5-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, fidelity_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, fidelity_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"fidelity\")\n",
        "plt.title(\"Comparison of fidelities\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9f17acd5",
      "metadata": {},
      "source": [
        "## Large-scale hardware example\n",
        "\n",
        "In this section, we benchmark the quantum kernel workflow with and without fractional gates on quantum hardware with up to 40 qubits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fd68378c",
      "metadata": {},
      "source": [
        "### Step 1-4 combined\n",
        "\n",
        "The workflow follows the same structure as the small-scale example. We transpile all circuits with and without fractional gates, collect metrics, and then submit the circuits to real quantum hardware.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "4431bf56",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "job id (w/ fractional gates): d8uasitbh0os73eqnpig\n"
          ]
        }
      ],
      "source": [
        "# -------------------------Step 1-------------------------\n",
        "qubits = list(range(4, 44, 4))\n",
        "circuits = [quantum_kernel(i, reps=reps) for i in qubits]\n",
        "params = [random_parameters(circ) for circ in circuits]\n",
        "b_qc = [\n",
        "    circ.assign_parameters(param) for circ, param in zip(circuits, params)\n",
        "]\n",
        "\n",
        "\n",
        "def benchmark(b_qc, backend):\n",
        "    # -------------------------Step 2-------------------------\n",
        "    pm = generate_preset_pass_manager(optimization_level, backend=backend)\n",
        "    if \"rzz\" in backend.target.operation_names:\n",
        "        # workaround until https://github.com/Qiskit/qiskit-ibm-runtime/issues/2441 is resolved\n",
        "        pm.post_optimization = PassManager(\n",
        "            [\n",
        "                FoldRzzAngle(),\n",
        "                Optimize1qGatesDecomposition(target=backend.target),\n",
        "                RemoveIdentityEquivalent(target=backend.target),\n",
        "            ]\n",
        "        )\n",
        "    t_qc = pm.run(b_qc)\n",
        "    nnl = [qc.num_nonlocal_gates() for qc in t_qc]\n",
        "    depth = [qc.depth() for qc in t_qc]\n",
        "    duration = [\n",
        "        qc.estimate_duration(backend_f.target, unit=\"u\") for qc in t_qc\n",
        "    ]\n",
        "\n",
        "    # -------------------------Step 3-------------------------\n",
        "    sampler = SamplerV2(mode=backend)\n",
        "    sampler.options.dynamical_decoupling.enable = True\n",
        "    sampler.options.dynamical_decoupling.sequence_type = \"XY4\"\n",
        "    sampler.options.dynamical_decoupling.skip_reset_qubits = True\n",
        "    sampler.options.environment.job_tags = [\"TUT_FG\"]\n",
        "    job = sampler.run(t_qc, shots=shots)\n",
        "    job_id = job.job_id()\n",
        "    return nnl, depth, duration, job_id\n",
        "\n",
        "\n",
        "def postprocessing(job_id: str):\n",
        "    # -------------------------Step 4-------------------------\n",
        "    job = service.job(job_id)\n",
        "    result = job.result()\n",
        "    fidelities = [fidelity(result=res) for res in result]\n",
        "    usage = job.usage()\n",
        "    return fidelities, usage\n",
        "\n",
        "\n",
        "backend_f = service.backend(backend_name, use_fractional_gates=True)\n",
        "nnl_f, depth_f, duration_f, job_id_f = benchmark(\n",
        "    b_qc, backend_f\n",
        ")  # step 2 & 3\n",
        "print(\"job id (w/ fractional gates):\", job_id_f)\n",
        "fidelity_f, usage_f = postprocessing(job_id_f)  # step 4"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "4a5d15a2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "job id (w/o fractional gates): d8uav3lposuc738pruug\n"
          ]
        }
      ],
      "source": [
        "backend_c = service.backend(backend_name, use_fractional_gates=False)\n",
        "nnl_c, depth_c, duration_c, job_id_c = benchmark(b_qc, backend_c)\n",
        "print(\"job id (w/o fractional gates):\", job_id_c)\n",
        "fidelity_c, usage_c = postprocessing(job_id_c)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9f78441e",
      "metadata": {},
      "source": [
        "We then compare metrics.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "id": "b409e8d3",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x12461e660>"
            ]
          },
          "execution_count": 26,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/b409e8d3-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, depth_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, depth_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"depth\")\n",
        "plt.title(\"Comparison of depths\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "09f91f0f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x11f2ac980>"
            ]
          },
          "execution_count": 27,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/09f91f0f-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, duration_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, duration_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"duration (µs)\")\n",
        "plt.title(\"Comparison of durations\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 28,
      "id": "c9308517",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x125c91be0>"
            ]
          },
          "execution_count": 28,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/c9308517-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, nnl_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, nnl_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"number of non-local gates\")\n",
        "plt.title(\"Comparison of numbers of non-local gates\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 29,
      "id": "234731d4",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x11fcf6e40>"
            ]
          },
          "execution_count": 29,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/234731d4-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(qubits, fidelity_c, \"-o\", label=\"no fractional gates\")\n",
        "plt.plot(qubits, fidelity_f, \"-o\", label=\"with fractional gates\")\n",
        "plt.xlabel(\"number of qubits\")\n",
        "plt.ylabel(\"fidelity\")\n",
        "plt.title(\"Comparison of fidelities\")\n",
        "plt.grid()\n",
        "plt.legend()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d38b9fe1",
      "metadata": {},
      "source": [
        "We compare the QPU usage time with and without fractional gates. The results in the following cell show that the QPU usage times are almost identical.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "id": "793326ca",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "no fractional gates: 8 seconds\n",
            "fractional gates: 8 seconds\n"
          ]
        }
      ],
      "source": [
        "print(f\"no fractional gates: {usage_c} seconds\")\n",
        "print(f\"fractional gates: {usage_f} seconds\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "efe18f80",
      "metadata": {},
      "source": [
        "## Advanced topic: Using only fractional RX gates\n",
        "\n",
        "The need for the modified workflow when using fractional gates primarily stems from the restriction on RZZ gate angles.\n",
        "However, if you use only the fractional RX gates and exclude the fractional RZZ gates, you can continue to follow the standard Qiskit patterns workflow.\n",
        "This approach can still offer meaningful benefits, particularly in circuits that involve a large number of RX gates and U gates, by reducing the overall gate count and potentially improving performance.\n",
        "In this section, we demonstrate how to optimize your circuits using only fractional RX gates, while omitting RZZ gates.\n",
        "\n",
        "To support this, we provide a utility function that allows you to disable a specific basis gate in a Target object.\n",
        "Here, we use it to disable RZZ gates.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "ab43ba23",
      "metadata": {},
      "outputs": [],
      "source": [
        "def remove_instruction_from_target(target: Target, gate_name: str) -> Target:\n",
        "    new_target = Target(\n",
        "        description=target.description,\n",
        "        num_qubits=target.num_qubits,\n",
        "        dt=target.dt,\n",
        "        granularity=target.granularity,\n",
        "        min_length=target.min_length,\n",
        "        pulse_alignment=target.pulse_alignment,\n",
        "        acquire_alignment=target.acquire_alignment,\n",
        "        qubit_properties=target.qubit_properties,\n",
        "        concurrent_measurements=target.concurrent_measurements,\n",
        "    )\n",
        "\n",
        "    for name, qarg_map in target.items():\n",
        "        if name == gate_name:\n",
        "            continue\n",
        "        instruction = target.operation_from_name(name)\n",
        "        if qarg_map == {None: None}:\n",
        "            qarg_map = None\n",
        "        new_target.add_instruction(instruction, qarg_map, name=name)\n",
        "    return new_target"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7f689a02",
      "metadata": {},
      "source": [
        "We use a circuit consisting of U, CZ, and RZZ gates as an example.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 32,
      "id": "6b812497",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/6b812497-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 32,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = n_local(3, \"u\", \"cz\", \"linear\", reps=1)\n",
        "qc.rzz(1.1, 0, 1)\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fa9dc1c4",
      "metadata": {},
      "source": [
        "We first transpile the circuit for a backend that does not support fractional gates.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "id": "9e8e0709",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OrderedDict({'rz': 23, 'sx': 16, 'cz': 4})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/9e8e0709-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 33,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm_c = generate_preset_pass_manager(\n",
        "    optimization_level=optimization_level, backend=backend_c\n",
        ")\n",
        "t_qc = pm_c.run(qc)\n",
        "print(t_qc.count_ops())\n",
        "t_qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bd0e24da",
      "metadata": {},
      "source": [
        "Then, we transpile the same circuit using fractional RX gates, while excluding RZZ gates.\n",
        "This results in a slight reduction in the total gate count, thanks to the more efficient implementation of the RX gates.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "id": "db45feb0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OrderedDict({'rz': 22, 'sx': 14, 'cz': 4, 'rx': 1})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/db45feb0-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 34,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "backend_f = service.backend(backend_name, use_fractional_gates=True)\n",
        "target = remove_instruction_from_target(backend_f.target, \"rzz\")\n",
        "pm_f = generate_preset_pass_manager(\n",
        "    optimization_level=optimization_level,\n",
        "    target=target,\n",
        ")\n",
        "t_qc = pm_f.run(qc)\n",
        "print(t_qc.count_ops())\n",
        "t_qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "15140636",
      "metadata": {},
      "source": [
        "### Optimize U gates with fractional RX gates\n",
        "\n",
        "In this section, we demonstrate how to optimize U gates using fractional RX gates, building on the same circuit introduced in the previous section.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3f73cbda",
      "metadata": {},
      "source": [
        "We transpile the circuit using only fractional RX gates, excluding RZZ gates.\n",
        "By introducing a custom decomposition rule, as shown in the following,\n",
        "we can reduce the number of single-qubit gates required to implement a U gate.\n",
        "\n",
        "This feature is currently under discussion in this [GitHub issue](https://github.com/Qiskit/qiskit/issues/13455).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 35,
      "id": "0f0c6d87",
      "metadata": {},
      "outputs": [],
      "source": [
        "# special decomposition rule for UGate\n",
        "x = ParameterVector(\"x\", 3)\n",
        "zxz = QuantumCircuit(1)\n",
        "zxz.rz(x[2] - np.pi / 2, 0)\n",
        "zxz.rx(x[0], 0)\n",
        "zxz.rz(x[1] + np.pi / 2, 0)\n",
        "DEFAULT_EQUIVALENCE_LIBRARY.add_equivalence(UGate(x[0], x[1], x[2]), zxz)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "91c824d8",
      "metadata": {},
      "source": [
        "Next, we apply the transpiler using `constructor-beta` translation provided by the `qiskit-basis-constructor` package.\n",
        "As a result, the total number of gates is reduced compared to the previous transpilation.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 36,
      "id": "b19aae7c",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OrderedDict({'rz': 16, 'rx': 9, 'cz': 4})\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/fractional-gates/extracted-outputs/b19aae7c-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 36,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm_f = generate_preset_pass_manager(\n",
        "    optimization_level=optimization_level,\n",
        "    target=target,\n",
        "    translation_method=\"constructor-beta\",\n",
        ")\n",
        "t_qc = pm_f.run(qc)\n",
        "print(t_qc.count_ops())\n",
        "t_qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "23ad4615",
      "metadata": {},
      "source": [
        "## Next steps\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recommendations\">\n",
        "  If you found this work interesting, you might be interested in the following material:\n",
        "\n",
        "  * [Fractional gates](/docs/guides/fractional-gates) guide\n",
        "  * [When *not* to use fractional gates](/docs/guides/fractional-gates#when-not-to-use)\n",
        "  * [`FoldRzzAngle`](/docs/api/qiskit-ibm-runtime/transpiler-passes-fold-rzz-angle) transpiler pass API reference\n",
        "  * The [Quantum kernel training](/docs/tutorials/quantum-kernel-training) tutorial\n",
        "  * The [Quantum kernels](/learning/courses/quantum-machine-learning/quantum-kernel-methods) lesson in the Quantum machine learning course\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3"
    },
    "hours": 1,
    "qpuSeconds": 30
  },
  "nbformat": 4,
  "nbformat_minor": 5
}