{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "alleged-prairie",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Utilidade III\"\n",
        "description: \"Esta lição trata da construção de um circuito GHZ para 20 qubits ou mais, de modo que, após a medição, a fidelidade do estado GHZ sobre um 0.5 e.\"\n",
        "---\n",
        "\n",
        "<span id=\"utility-scale-experiment-iii\" />\n",
        "\n",
        "# Experimento em escala utilitária III\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  Toshinari Itoko, Tamiya Onodera, Kifumi Numata (19 de julho de 2024)\n",
        "\n",
        "  [Baixe o pdf](https://ibm.ent.box.com/public/static/fw1538dogvyv0qbfqg8tan1k2fs27mfv.zip) da palestra original. Observe que alguns trechos de código podem se tornar obsoletos, pois são imagens estáticas.\n",
        "\n",
        "  *O tempo aproximado da QPU para executar esse primeiro experimento é de 12 m 30 s. Há um experimento adicional abaixo que requer aproximadamente 4 m.*\n",
        "\n",
        "  (Observação: este notebook pode não ser avaliado no tempo permitido no Open Plan. Certifique-se de usar os recursos de computação quântica com sabedoria)\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "20483d1a-6b31-4569-b817-c9faecc8823b",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'2.0.2'"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit\n",
        "\n",
        "qiskit.__version__"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "fa30363a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'0.40.1'"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit_ibm_runtime\n",
        "\n",
        "qiskit_ibm_runtime.__version__"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "78f23522",
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import rustworkx as rx\n",
        "\n",
        "from qiskit import QuantumCircuit\n",
        "from qiskit.visualization import plot_histogram\n",
        "from qiskit.visualization import plot_gate_map\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "from qiskit.providers import BackendV2\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime import Sampler, Estimator, Batch, SamplerOptions"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "948a9ac1-2ad3-4969-8b39-bb3d697ad6bb",
      "metadata": {},
      "source": [
        "<span id=\"1-introduction\" />\n",
        "\n",
        "## 1. Introdução\n",
        "\n",
        "Vamos analisar brevemente os estados do GHZ e que tipo de distribuição você pode esperar do `Sampler` aplicado a um deles. Em seguida, explicaremos explicitamente o objetivo desta lição.\n",
        "\n",
        "<span id=\"11-ghz-state\" />\n",
        "\n",
        "### 1.1 Estado GHZ\n",
        "\n",
        "O estado GHZ (Greenberger-Horne-Zeilinger state) para $n$ qubits é definido como\n",
        "\n",
        "$$\n",
        "\\frac{1}{\\sqrt 2}(|0\\rangle ^ {\\otimes n}+ |1\\rangle^ {\\otimes n})\n",
        "$$\n",
        "\n",
        "Naturalmente, ele pode ser criado para 6 qubits com o seguinte circuito quântico.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "1bf914c5-e1c6-4664-99c2-69dea3961114",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/1bf914c5-e1c6-4664-99c2-69dea3961114-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "N = 6\n",
        "qc = QuantumCircuit(N, N)\n",
        "\n",
        "qc.h(0)\n",
        "for i in range(N - 1):\n",
        "    qc.cx(0, i + 1)\n",
        "\n",
        "# qc.measure_all()\n",
        "qc.barrier()\n",
        "qc.measure(list(range(N)), list(range(N)))\n",
        "\n",
        "qc.draw(output=\"mpl\", idle_wires=False, scale=0.5)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "7b4cb915-c901-4b6d-839b-2f1ae43601d7",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Depth: 7\n"
          ]
        }
      ],
      "source": [
        "print(\"Depth:\", qc.depth())"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c398d524",
      "metadata": {},
      "source": [
        "A profundidade não é muito grande, embora você saiba, pelas lições anteriores, que pode fazer melhor. Vamos escolher um backend e transpilar esse circuito.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "108bc369",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'ibm_kingston'"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(operational=True, simulator=False)\n",
        "backend.name\n",
        "# or\n",
        "# backend = service.least_busy(operational=True)\n",
        "# backend.name"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "2e003078-3707-44d9-86e8-bbc66b095e84",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/2e003078-3707-44d9-86e8-bbc66b095e84-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm = generate_preset_pass_manager(3, backend=backend)\n",
        "qc_transpiled = pm.run(qc)\n",
        "qc_transpiled.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "18d3524a-43ec-4163-8f53-8e9bf4421e06",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Depth: 27\n",
            "Two-qubit Depth: 11\n"
          ]
        }
      ],
      "source": [
        "print(\"Depth:\", qc_transpiled.depth())\n",
        "print(\n",
        "    \"Two-qubit Depth:\",\n",
        "    qc_transpiled.depth(filter_function=lambda x: x.operation.num_qubits == 2),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "109ff71e",
      "metadata": {},
      "source": [
        "Novamente, a profundidade transpilada de dois qubits não é muito grande. Mas para trabalhar com um estado GHZ em mais qubits, você claramente precisará pensar em otimizar o circuito. Vamos executar isso usando `Sampler` e ver o que um computador quântico real retorna.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "abd0654d-b2dc-4180-821c-6af4977a12e8",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "d147y20n2txg008jvv70\n"
          ]
        }
      ],
      "source": [
        "sampler = Sampler(mode=backend)\n",
        "shots = 40000\n",
        "job = sampler.run([qc_transpiled], shots=shots)\n",
        "job_id = job.job_id()\n",
        "print(job_id)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "f0073d8b-1ad8-4bb7-a2d2-754ce2876ffd",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'DONE'"
            ]
          },
          "execution_count": 12,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "job.status()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "8ab5b37f-fb87-40a8-8e13-0c6cb3154f64",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/8ab5b37f-fb87-40a8-8e13-0c6cb3154f64-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 13,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "job = service.job(job_id)\n",
        "result = job.result()\n",
        "plot_histogram(result[0].data.c.get_counts(), figsize=(30, 5))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9965c7c1-babd-444d-8436-2a63bcbe79af",
      "metadata": {},
      "source": [
        "Esse é o resultado do circuito GHZ de 6 qubits. Como você pode ver, os estados de todos os $|0\\rangle$ 's e todos os $|1\\rangle$ 's são dominantes, mas os erros são substanciais. Vamos tentar ver o tamanho do circuito GHZ que você pode fazer com um dispositivo Eagle e, ao mesmo tempo, obter resultados em que os estados corretos tenham pelo menos mais de 50% de probabilidade.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9942f911-bfbf-4a16-8349-05bc490885e6",
      "metadata": {},
      "source": [
        "<span id=\"12-your-goal\" />\n",
        "\n",
        "### 1.2 Seu objetivo\n",
        "\n",
        "Construa um circuito GHZ para 20 qubits ou mais, de modo que, após a medição, **a fidelidade de seu estado GHZ seja > 0.5**\n",
        "Observação:\n",
        "\n",
        "* Você precisa usar um dispositivo Eagle (`min_num_qubits=127`) e definir o número de disparos como 40.000.\n",
        "* Você deve executar o circuito GHZ usando a função `execute_ghz_fidelity` e calcular a fidelidade usando a função `check_ghz_fidelity_from_jobs` .\n",
        "\n",
        "Este é um exercício independente, no qual você aproveita o que aprendeu até agora neste curso.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a316416f-d6c5-4183-b4ef-d6170681d8a4",
      "metadata": {},
      "outputs": [],
      "source": [
        "def execute_ghz_fidelity(\n",
        "    ghz_circuit: QuantumCircuit,  # Quantum circuit to create GHZ state (Circuit after Routing or without Routing), Classical register name is \"c\"\n",
        "    physical_qubits: list[int],  # Physical qubits to represent GHZ state\n",
        "    backend: BackendV2,\n",
        "    sampler_options: dict | SamplerOptions | None = None,\n",
        "):\n",
        "    N_SHOTS = 40_000\n",
        "    N = len(physical_qubits)\n",
        "    base_circuit = ghz_circuit.remove_final_measurements(inplace=False)\n",
        "    # M_k measurement circuits\n",
        "    mk_circuits = []\n",
        "    for k in range(1, N + 1):\n",
        "        circuit = base_circuit.copy()\n",
        "        # change measurement basis\n",
        "        for q in physical_qubits:\n",
        "            circuit.rz(-k * np.pi / N, q)\n",
        "            circuit.h(q)\n",
        "        mk_circuits.append(circuit)\n",
        "\n",
        "    obs = SparsePauliOp.from_sparse_list(\n",
        "        [(\"Z\" * N, physical_qubits, 1)], num_qubits=backend.num_qubits\n",
        "    )\n",
        "    job_ids = []\n",
        "    pm1 = generate_preset_pass_manager(1, backend=backend)\n",
        "    org_transpiled = pm1.run(ghz_circuit)\n",
        "    mk_transpiled = pm1.run(mk_circuits)\n",
        "    with Batch(backend=backend):\n",
        "        sampler = Sampler(options=sampler_options)\n",
        "        sampler.options.twirling.enable_measure = True\n",
        "        job = sampler.run([org_transpiled], shots=N_SHOTS)\n",
        "        job_ids.append(job.job_id())\n",
        "        # print(f\"Sampler job id: {job.job_id()}, shots={N_SHOTS}\")\n",
        "        estimator = Estimator()  # TREX is applied as default\n",
        "        estimator.options.dynamical_decoupling.enable = True\n",
        "        estimator.options.execution.rep_delay = 0.0005\n",
        "        estimator.options.twirling.enable_measure = True\n",
        "        job2 = estimator.run([(circ, obs) for circ in mk_transpiled], precision=1 / 100)\n",
        "        job_ids.append(job2.job_id())\n",
        "        # print(\"Estimator job id:\", job2.job_id())\n",
        "        return [job.job_id(), job2.job_id()]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "f86e4288-9e65-4dd5-81dd-149f1e98d217",
      "metadata": {},
      "outputs": [],
      "source": [
        "def check_ghz_fidelity_from_jobs(\n",
        "    sampler_job,\n",
        "    estimator_job,\n",
        "    num_qubits,\n",
        "    shots=40_000,\n",
        "):\n",
        "    N = num_qubits\n",
        "    sampler_result = sampler_job.result()\n",
        "    counts = sampler_result[0].data.c.get_counts()\n",
        "    all_zero = counts.get(\"0\" * N, 0) / shots\n",
        "    all_one = counts.get(\"1\" * N, 0) / shots\n",
        "    top3 = sorted(counts, key=counts.get, reverse=True)[:3]\n",
        "    print(\n",
        "        f\"N={N}: |00..0>: {counts.get('0'*N, 0)}, |11..1>: {counts.get('1'*N, 0)}, |3rd>: {counts.get(top3[2], 0)} ({top3[2]})\"\n",
        "    )\n",
        "    print(f\"P(|00..0>)={all_zero}, P(|11..1>)={all_one}\")\n",
        "\n",
        "    estimator_result = estimator_job.result()\n",
        "    non_diagonal = (1 / N) * sum(\n",
        "        (-1) ** k * estimator_result[k - 1].data.evs for k in range(1, N + 1)\n",
        "    )\n",
        "    print(f\"REM: Coherence (non-diagonal): {non_diagonal:.6f}\")\n",
        "    fidelity = 0.5 * (all_zero + all_one + non_diagonal)\n",
        "    sigma = 0.5 * np.sqrt(\n",
        "        (1 - all_zero - all_one) * (all_zero + all_one) / shots\n",
        "        + sum(estimator_result[k].data.stds ** 2 for k in range(N)) / (N * N)\n",
        "    )\n",
        "    print(f\"GHZ fidelity = {fidelity:.6f} ± {sigma:.6f}\")\n",
        "    if fidelity - 2 * sigma > 0.5:\n",
        "        print(\"GME (genuinely multipartite entangled) test: Passed\")\n",
        "    else:\n",
        "        print(\"GME (genuinely multipartite entangled) test: Failed\")\n",
        "    return {\n",
        "        \"fidelity\": fidelity,\n",
        "        \"sigma\": sigma,\n",
        "        \"shots\": shots,\n",
        "        \"job_ids\": [sampler_job.job_id(), estimator_job.job_id()],\n",
        "    }"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ad35a576-9ae4-4d00-af4d-3af0974101e9",
      "metadata": {},
      "source": [
        "Neste notebook, aplicaremos três estratégias para criar bons estados GHZ usando 16 qubits e 30 qubits. Essas abordagens se baseiam em estratégias que você já conhece de lições anteriores.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "371c0d79",
      "metadata": {},
      "source": [
        "<span id=\"2-strategy-1-noise-aware-qubit-selection\" />\n",
        "\n",
        "## 2. Estratégia 1. Seleção de qubits sensível ao ruído\n",
        "\n",
        "Primeiro, especificamos um backend. Como trabalharemos extensivamente com as propriedades de um backend específico, é uma boa ideia especificar um backend, em vez de usar a opção `least_busy` .\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 36,
      "id": "119bd751",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Device ibm_strasbourg Loaded with 127 qubits\n",
            "Two Qubit Gate: ecr\n"
          ]
        }
      ],
      "source": [
        "backend = service.backend(\"ibm_strasbourg\")  # eagle\n",
        "twoq_gate = \"ecr\"\n",
        "print(f\"Device {backend.name} Loaded with {backend.num_qubits} qubits\")\n",
        "print(f\"Two Qubit Gate: {twoq_gate}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "997d7bc9",
      "metadata": {},
      "source": [
        "Vamos construir um circuito que envolve muitas portas de dois qubits. Faz sentido usarmos os qubits que têm os menores erros ao implementar essas portas de dois qubits. Encontrar a melhor \"cadeia de qubits\" com base nos erros relatados em 2q-gate é um problema não trivial. Mas podemos definir algumas funções para nos ajudar a determinar os melhores qubits a serem usados.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 37,
      "id": "7bc47055",
      "metadata": {},
      "outputs": [],
      "source": [
        "coupling_map = backend.target.build_coupling_map(twoq_gate)\n",
        "G = coupling_map.graph"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8615f6d8",
      "metadata": {},
      "outputs": [],
      "source": [
        "def to_edges(path):  # create edges list from node paths\n",
        "    edges = []\n",
        "    prev_node = None\n",
        "    for node in path:\n",
        "        if prev_node is not None:\n",
        "            if G.has_edge(prev_node, node):\n",
        "                edges.append((prev_node, node))\n",
        "            else:\n",
        "                edges.append((node, prev_node))\n",
        "        prev_node = node\n",
        "    return edges\n",
        "\n",
        "\n",
        "def path_fidelity(path, correct_by_duration: bool = True, readout_scale: float = None):\n",
        "    \"\"\"Compute an estimate of the total fidelity of 2-qubit gates on a path.\n",
        "    If `correct_by_duration` is true, each gate fidelity is worsen by\n",
        "    scale = max_duration / duration, that is, gate_fidelity^scale.\n",
        "    If `readout_scale` > 0 is supplied, readout_fidelity^readout_scale\n",
        "    for each qubit on the path is multiplied to the total fielity.\n",
        "    The path is given in node indices form, for example, [0, 1, 2].\n",
        "    An external function `to_edges` is used to obtain edge list, for example, [(0, 1), (1, 2)].\"\"\"\n",
        "    path_edges = to_edges(path)\n",
        "    max_duration = max(backend.target[twoq_gate][qs].duration for qs in path_edges)\n",
        "\n",
        "    def gate_fidelity(qpair):\n",
        "        duration = backend.target[twoq_gate][qpair].duration\n",
        "        scale = max_duration / duration if correct_by_duration else 1.0\n",
        "        # 1.25 = (d+1)/d with d = 4\n",
        "        return max(0.25, 1 - (1.25 * backend.target[twoq_gate][qpair].error)) ** scale\n",
        "\n",
        "    def readout_fidelity(qubit):\n",
        "        return max(0.25, 1 - backend.target[\"measure\"][(qubit,)].error)\n",
        "\n",
        "    total_fidelity = np.prod(\n",
        "        [gate_fidelity(qs) for qs in path_edges]\n",
        "    )  # two qubits gate fidelity for each path\n",
        "    if readout_scale:\n",
        "        total_fidelity *= (\n",
        "            np.prod([readout_fidelity(q) for q in path]) ** readout_scale\n",
        "        )  # multiply readout fidelity\n",
        "    return total_fidelity\n",
        "\n",
        "\n",
        "def flatten(paths, cutoff=None):  # cutoff is for not making run time too large\n",
        "    return [\n",
        "        path\n",
        "        for s, s_paths in paths.items()\n",
        "        for t, st_paths in s_paths.items()\n",
        "        for path in st_paths[:cutoff]\n",
        "        if s < t\n",
        "    ]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 39,
      "id": "be1971a0",
      "metadata": {},
      "outputs": [],
      "source": [
        "N = 16  # Number of qubits to use in the GHZ circuit\n",
        "num_qubits_in_chain = N"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d95a798a-90cc-42d8-9461-ab5bd5440aef",
      "metadata": {},
      "source": [
        "Usaremos as funções acima para encontrar todos os caminhos simples de N qubits entre todos os pares de nós no gráfico (Referência: [all\\_pairs\\_all\\_simple\\_paths](https://www.rustworkx.org/apiref/rustworkx.all_pairs_all_simple_paths.html#rustworkx-all-pairs-all-simple-paths) ).\n",
        "\n",
        "Em seguida, usando a função `path_fidelity` criada acima, encontraremos a melhor cadeia de qubits que tenha a maior fidelidade de caminho.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 40,
      "id": "e0b410e7",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Selecting the best from 6046 candidate paths\n",
            "Predicted (best possible) process fidelity: 0.8929026784775056\n",
            "CPU times: user 284 ms, sys: 10.9 ms, total: 295 ms\n",
            "Wall time: 295 ms\n"
          ]
        }
      ],
      "source": [
        "from functools import partial\n",
        "\n",
        "%%time\n",
        "paths = rx.all_pairs_all_simple_paths(\n",
        "    G.to_undirected(multigraph=False),\n",
        "    min_depth=num_qubits_in_chain,\n",
        "    cutoff=num_qubits_in_chain,\n",
        ")\n",
        "paths = flatten(paths, cutoff=25)  # If you have time, you could set a larger cutoff.\n",
        "if not paths:\n",
        "    raise Exception(\n",
        "        f\"No qubit chain with length={num_qubits_in_chain} exists in {backend.name}. Try smaller num_qubits_in_chain.\"\n",
        "    )\n",
        "\n",
        "print(f\"Selecting the best from {len(paths)} candidate paths\")\n",
        "\n",
        "best_qubit_chain = max(\n",
        "    paths, key=partial(path_fidelity, correct_by_duration=True, readout_scale=1.0)\n",
        ")\n",
        "assert len(best_qubit_chain) == num_qubits_in_chain\n",
        "print(f\"Predicted (best possible) process fidelity: {path_fidelity(best_qubit_chain)}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 41,
      "id": "efc3c14d",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([55, 49, 48, 47, 46, 45, 54, 64, 65, 66, 73, 85, 86, 87, 88, 89],\n",
              "      dtype=uint64)"
            ]
          },
          "execution_count": 41,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "np.array(best_qubit_chain)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9d364986-c387-4d0d-874c-9a7f10634394",
      "metadata": {},
      "source": [
        "Vamos traçar a melhor cadeia de qubits, mostrada em rosa, no diagrama do mapa de acoplamento.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 42,
      "id": "a1c164a4",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/a1c164a4-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 42,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qubit_color = []\n",
        "for i in range(133):\n",
        "    if i in best_qubit_chain:\n",
        "        qubit_color.append(\"#ff00dd\")  # pink\n",
        "    else:\n",
        "        qubit_color.append(\"#8c00ff\")  # purple\n",
        "plot_gate_map(\n",
        "    backend, qubit_color=qubit_color, qubit_size=50, font_size=25, figsize=(6, 6)\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4e66abc7",
      "metadata": {},
      "source": [
        "<span id=\"21-build-a-ghz-circuit-on-the-best-qubit-chain\" />\n",
        "\n",
        "### 2.1 Construa um circuito GHZ na melhor cadeia de qubits\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "273f469d-3273-40ee-922d-4ad43e1d53ad",
      "metadata": {},
      "source": [
        "Escolhemos um qubit no meio da cadeia para aplicar primeiro a porta H. Isso deve reduzir a profundidade do circuito em cerca de metade.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 43,
      "id": "1336fba0",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/1336fba0-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 43,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz1 = QuantumCircuit(max(best_qubit_chain) + 1, N)\n",
        "ghz1.h(best_qubit_chain[N // 2])\n",
        "for i in range(N // 2, 0, -1):\n",
        "    ghz1.cx(best_qubit_chain[i], best_qubit_chain[i - 1])\n",
        "for i in range(N // 2, N - 1, +1):\n",
        "    ghz1.cx(best_qubit_chain[i], best_qubit_chain[i + 1])\n",
        "ghz1.barrier()  # for visualization\n",
        "ghz1.measure(best_qubit_chain, list(range(N)))\n",
        "ghz1.draw(output=\"mpl\", idle_wires=False, scale=0.5, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 44,
      "id": "facf25d3-add9-42e2-aeba-506b24a8e516",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "10"
            ]
          },
          "execution_count": 44,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz1.depth()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 45,
      "id": "71874b6d-eb9b-4ff5-b673-944191f67010",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/71874b6d-eb9b-4ff5-b673-944191f67010-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 45,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm = generate_preset_pass_manager(1, backend=backend)\n",
        "ghz1_transpiled = pm.run(ghz1)\n",
        "ghz1_transpiled.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 46,
      "id": "9e1609a4-2b1c-43dc-99e0-ed62dbeb89fb",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Depth: 27\n",
            "Two-qubit Depth: 8\n"
          ]
        }
      ],
      "source": [
        "print(\"Depth:\", ghz1_transpiled.depth())\n",
        "print(\n",
        "    \"Two-qubit Depth:\",\n",
        "    ghz1_transpiled.depth(filter_function=lambda x: x.operation.num_qubits == 2),\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 47,
      "id": "5a3ad726-e6fb-4de5-a674-f7373845c917",
      "metadata": {},
      "outputs": [],
      "source": [
        "opts = SamplerOptions()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "0178e4f4-cc5f-44f9-97b7-7393765e53f1",
      "metadata": {},
      "outputs": [],
      "source": [
        "res = execute_ghz_fidelity(\n",
        "    ghz_circuit=ghz1,\n",
        "    physical_qubits=best_qubit_chain,\n",
        "    backend=backend,\n",
        "    sampler_options=opts,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 55,
      "id": "d6368f70-1fb7-45ad-bd90-f3ca1b1795dc",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "DONE DONE\n"
          ]
        }
      ],
      "source": [
        "job_s = service.job(res[0])  # Use your job id showed above.\n",
        "job_e = service.job(res[1])\n",
        "print(job_s.status(), job_e.status())"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cfebc599-d70d-4f1d-95b2-4c2ec60b1ee5",
      "metadata": {},
      "source": [
        "Tenha o cuidado de executar a próxima célula depois que os status dos trabalhos acima se tornarem \"DONE\", para mostrar o resultado usando a função `check_ghz_fidelity_from_jobs` .\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 56,
      "id": "7029c582-6b41-4df5-b175-e098e0ee2e74",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "N=16: |00..0>: 153, |11..1>: 8681, |3rd>: 2262 (1111111111101111)\n",
            "P(|00..0>)=0.003825, P(|11..1>)=0.217025\n",
            "REM: Coherence (non-diagonal): 0.073809\n",
            "GHZ fidelity = 0.147329 ± 0.002438\n",
            "GME (genuinely multipartite entangled) test: Failed\n"
          ]
        }
      ],
      "source": [
        "N = 16\n",
        "# Check fidelity from job IDs\n",
        "res = check_ghz_fidelity_from_jobs(\n",
        "    sampler_job=job_s,\n",
        "    estimator_job=job_e,\n",
        "    num_qubits=N,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 57,
      "id": "236126cb",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/236126cb-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 57,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "result = job_s.result()\n",
        "plot_histogram(result[0].data.c.get_counts(), figsize=(30, 5))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3af2c82d-183e-4df0-be45-17fd32ea6c2e",
      "metadata": {},
      "source": [
        "Esse resultado não atende aos critérios. Vamos passar para a próxima ideia.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ce16e4cb",
      "metadata": {},
      "source": [
        "<span id=\"3-strategy-2-balanced-tree-of-qubits\" />\n",
        "\n",
        "## 3. Estratégia 2. Árvore equilibrada de qubits\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "45d96784",
      "metadata": {},
      "source": [
        "A próxima ideia é encontrar uma árvore equilibrada de qubits. Usando a árvore em vez da corrente, a profundidade do circuito deve ser menor. Antes disso, removemos os nós com erros de leitura \"ruins\" e as bordas com erros de porta \"ruins\" do gráfico de acoplamento.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 58,
      "id": "632768ac",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Bad readout qubits: [19, 28, 41, 72, 91, 114, 120]\n",
            "Bad ECR gates: []\n"
          ]
        }
      ],
      "source": [
        "BAD_READOUT_ERROR_THRESHOLD = 0.1\n",
        "BAD_ECRGATE_ERROR_THRESHOLD = 0.1\n",
        "bad_readout_qubits = [\n",
        "    q\n",
        "    for q in range(backend.num_qubits)\n",
        "    if backend.target[\"measure\"][(q,)].error > BAD_READOUT_ERROR_THRESHOLD\n",
        "]\n",
        "bad_ecrgate_edges = [\n",
        "    qpair\n",
        "    for qpair in backend.target[\"ecr\"]\n",
        "    if backend.target[\"ecr\"][qpair].error > BAD_ECRGATE_ERROR_THRESHOLD\n",
        "]\n",
        "print(\"Bad readout qubits:\", bad_readout_qubits)\n",
        "print(\"Bad ECR gates:\", bad_ecrgate_edges)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 59,
      "id": "6775ea6b",
      "metadata": {},
      "outputs": [],
      "source": [
        "g = backend.coupling_map.graph.copy().to_undirected()\n",
        "g.remove_edges_from(\n",
        "    bad_ecrgate_edges\n",
        ")  # remove edge first (otherwise might fail with a NoEdgeBetweenNodes error)\n",
        "g.remove_nodes_from(bad_readout_qubits)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2247eb6b-a909-4fa1-91f4-40dfdf5f8d77",
      "metadata": {},
      "source": [
        "Vamos desenhar o gráfico do mapa de acoplamento sem as bordas ruins e os qubits ruins.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 60,
      "id": "18825a87-4679-4027-af58-31efd24a9a60",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/18825a87-4679-4027-af58-31efd24a9a60-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 60,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qubit_color = []\n",
        "for i in range(133):\n",
        "    if i in bad_readout_qubits:\n",
        "        qubit_color.append(\"#000000\")  # black\n",
        "    else:\n",
        "        qubit_color.append(\"#8c00ff\")  # purple\n",
        "line_color = []\n",
        "for e in backend.target.build_coupling_map().get_edges():\n",
        "    if e in bad_ecrgate_edges:\n",
        "        line_color.append(\"#ffffff\")  # white\n",
        "    else:\n",
        "        line_color.append(\"#888888\")  # gray\n",
        "plot_gate_map(\n",
        "    backend,\n",
        "    qubit_color=qubit_color,\n",
        "    line_color=line_color,\n",
        "    qubit_size=50,\n",
        "    font_size=25,\n",
        "    figsize=(6, 6),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5245dbee-e0fa-485d-a0fc-ce72b2739ccd",
      "metadata": {},
      "source": [
        "Tentamos criar um estado GHZ de 16 qubits como antes.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 61,
      "id": "1affd16e",
      "metadata": {},
      "outputs": [],
      "source": [
        "N = 16"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b0648130-ab85-477e-b754-94a3e28e2134",
      "metadata": {},
      "source": [
        "Chamamos a função `betweenness_centrality` para encontrar um qubit para o nó raiz. O nó com o maior valor de centralidade de intermediação está no centro do gráfico. Referência: [https://www.rustworkx.org/tutorial/betweenness\\_centrality.html](https://www.rustworkx.org/tutorial/betweenness_centrality.html)\n",
        "\n",
        "Ou você pode selecioná-lo manualmente.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 62,
      "id": "07ad8ee3-46f9-4c7b-ad96-5aaa45407999",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "66"
            ]
          },
          "execution_count": 62,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# central = 65 #Select the center node manually\n",
        "c_degree = dict(rx.betweenness_centrality(g))\n",
        "central = max(c_degree, key=c_degree.get)\n",
        "central"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5033164f-652a-4b72-a6f8-5fe52383e3f3",
      "metadata": {},
      "source": [
        "A partir do nó raiz, gere uma árvore por meio da pesquisa de amplitude primeiro (BFS). Referência: [https://qiskit.org/ecosystem/rustworkx/apiref/rustworkx.bfs\\_search.html #rustworkx-bfs-search](https://qiskit.org/ecosystem/rustworkx/apiref/rustworkx.bfs_search.html#rustworkx-bfs-search)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 63,
      "id": "9137e5c8",
      "metadata": {},
      "outputs": [],
      "source": [
        "class TreeEdgesRecorder(rx.visit.BFSVisitor):\n",
        "    def __init__(self, N):\n",
        "        self.edges = []\n",
        "        self.N = N\n",
        "\n",
        "    def tree_edge(self, edge):\n",
        "        self.edges.append(edge)\n",
        "        if len(self.edges) >= self.N - 1:\n",
        "            raise rx.visit.StopSearch()\n",
        "\n",
        "\n",
        "vis = TreeEdgesRecorder(N)\n",
        "rx.bfs_search(g, [central], vis)\n",
        "best_qubits = sorted(list(set(q for e in vis.edges for q in (e[0], e[1]))))\n",
        "# print('Tree edges:', vis.edges)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 64,
      "id": "69c447dc",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Qubits selected: [54, 55, 63, 64, 65, 66, 67, 68, 69, 70, 73, 83, 84, 85, 86, 87]\n"
          ]
        }
      ],
      "source": [
        "print(\"Qubits selected:\", best_qubits)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ea5f9be4-fb66-4231-a9df-b49a510cceb9",
      "metadata": {},
      "source": [
        "Vamos plotar os qubits selecionados, mostrados em rosa, no diagrama do mapa de acoplamento.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 65,
      "id": "ef18e037-a3ec-4370-bee7-bd71dbc12795",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/ef18e037-a3ec-4370-bee7-bd71dbc12795-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 65,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qubit_color = []\n",
        "for i in range(133):\n",
        "    if i in bad_readout_qubits:\n",
        "        qubit_color.append(\"#000000\")  # black\n",
        "    elif i in best_qubits:\n",
        "        qubit_color.append(\"#ff00dd\")  # pink\n",
        "    else:\n",
        "        qubit_color.append(\"#8c00ff\")  # purple\n",
        "plot_gate_map(\n",
        "    backend,\n",
        "    qubit_color=qubit_color,\n",
        "    line_color=line_color,\n",
        "    qubit_size=50,\n",
        "    font_size=25,\n",
        "    figsize=(6, 6),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c766256c-a9b8-41c1-ad23-1862f1e36b38",
      "metadata": {},
      "source": [
        "Vamos mostrar a estrutura de árvore dos qubits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 66,
      "id": "8758d3a6",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/8758d3a6-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 66,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from rustworkx.visualization import graphviz_draw\n",
        "\n",
        "tree = rx.PyDiGraph()\n",
        "tree.extend_from_weighted_edge_list(vis.edges)\n",
        "tree.remove_nodes_from([n for n in range(max(best_qubits) + 1) if n not in best_qubits])\n",
        "\n",
        "graphviz_draw(tree, method=\"dot\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 67,
      "id": "3bc4b071",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/3bc4b071-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 67,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz2 = QuantumCircuit(max(best_qubits) + 1, N)\n",
        "\n",
        "ghz2.h(tree.edge_list()[0][0])  # apply H-gate to the root node\n",
        "# Apply CNOT from the root node to the each edge.\n",
        "for u, v in tree.edge_list():\n",
        "    ghz2.cx(u, v)\n",
        "ghz2.barrier()  # for visualization\n",
        "ghz2.measure(best_qubits, list(range(N)))\n",
        "ghz2.draw(output=\"mpl\", idle_wires=False, scale=0.5)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 68,
      "id": "fd2978ee-b359-464e-bf7f-eed4a65b1203",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "8"
            ]
          },
          "execution_count": 68,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz2.depth()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 69,
      "id": "c490e37a-309a-43e3-9b18-3be7c7d8a957",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/c490e37a-309a-43e3-9b18-3be7c7d8a957-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 69,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm = generate_preset_pass_manager(1, backend=backend)\n",
        "ghz2_transpiled = pm.run(ghz2)\n",
        "ghz2_transpiled.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 70,
      "id": "376dfe4e-53c9-4eb5-988e-2bc7674ddcad",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Depth: 22\n",
            "Two-qubit Depth: 6\n"
          ]
        }
      ],
      "source": [
        "print(\"Depth:\", ghz2_transpiled.depth())\n",
        "print(\n",
        "    \"Two-qubit Depth:\",\n",
        "    ghz2_transpiled.depth(filter_function=lambda x: x.operation.num_qubits == 2),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f5681336-b72d-4ec9-a60e-2101fa42d87e",
      "metadata": {},
      "source": [
        "A profundidade do circuito agora é muito menor do que a da estrutura da cadeia.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "c56889ab-b8cd-4a7e-90f0-8a05d12e9f3f",
      "metadata": {},
      "outputs": [],
      "source": [
        "res = execute_ghz_fidelity(\n",
        "    ghz_circuit=ghz2,\n",
        "    physical_qubits=best_qubits,\n",
        "    backend=backend,\n",
        "    sampler_options=opts,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 74,
      "id": "daf011fe-853c-4e55-89ff-eeab38cb0de4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "DONE DONE\n"
          ]
        }
      ],
      "source": [
        "job_s = service.job(res[0])  # Use your job id showed above.\n",
        "job_e = service.job(res[1])\n",
        "print(job_s.status(), job_e.status())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 75,
      "id": "51aee0d4-c896-4d2b-843a-3c58ee7572bb",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "N=16: |00..0>: 9509, |11..1>: 10978, |3rd>: 1795 (1111110111111111)\n",
            "P(|00..0>)=0.237725, P(|11..1>)=0.27445\n",
            "REM: Coherence (non-diagonal): 0.606515\n",
            "GHZ fidelity = 0.559345 ± 0.003188\n",
            "GME (genuinely multipartite entangled) test: Passed\n"
          ]
        }
      ],
      "source": [
        "N = 16\n",
        "# Check fidelity from job IDs\n",
        "res = check_ghz_fidelity_from_jobs(\n",
        "    sampler_job=job_s,\n",
        "    estimator_job=job_e,\n",
        "    num_qubits=N,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7fe25d70-36e3-4442-b150-21ea47143050",
      "metadata": {},
      "source": [
        "Conseguimos passar nos critérios com a estrutura de árvore equilibrada!\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 76,
      "id": "cf8b4dac",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/cf8b4dac-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 76,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "result = job_s.result()\n",
        "plot_histogram(result[0].data.c.get_counts(), figsize=(30, 5))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "40bc77d5-be60-4360-9750-31d0f1459ab0",
      "metadata": {},
      "source": [
        "Agora, vamos tentar criar um estado GHZ maior: um estado GHZ de 30 qubit.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "816914ce-52dd-4df5-9943-0acc606240c3",
      "metadata": {},
      "source": [
        "<span id=\"31-n-=-30\" />\n",
        "\n",
        "### 3.1 N = 30\n",
        "\n",
        "Seguiremos a estrutura de [padrões do Qiskit](/docs/guides/intro-to-patterns).\n",
        "\n",
        "* Etapa 1: Mapear o problema para circuitos e operadores quânticos\n",
        "* Etapa 2: otimizar para o hardware de destino\n",
        "* Etapa 3: Executar no hardware de destino\n",
        "* Etapa 4: Resultados do pós-processamento\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "20e6b416-eee7-4728-9fef-0de34b5ecbac",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-problem-to-quantum-circuits-and-operators-and-step-2-optimize-for-target-hardware\" />\n",
        "\n",
        "#### Etapa 1: Mapear o problema para circuitos e operadores quânticos e Etapa 2: Otimizar para o hardware de destino\n",
        "\n",
        "Aqui, selecionamos o nó raiz manualmente.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 77,
      "id": "5fff1f72-062f-4c3c-84b9-87e3af368f31",
      "metadata": {},
      "outputs": [],
      "source": [
        "central = 62  # Select the center node manually\n",
        "# c_degree = dict(rx.betweenness_centrality(g))\n",
        "# central = max(c_degree, key=c_degree.get)\n",
        "# central"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 78,
      "id": "693e80bb-e967-41be-bd82-85e4346fd6aa",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Qubits selected: [34, 35, 42, 43, 44, 45, 46, 47, 48, 53, 54, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 71, 73, 77, 84, 85, 86]\n"
          ]
        }
      ],
      "source": [
        "N = 30\n",
        "\n",
        "vis = TreeEdgesRecorder(N)\n",
        "rx.bfs_search(g, [central], vis)\n",
        "best_qubits = sorted(list(set(q for e in vis.edges for q in (e[0], e[1]))))\n",
        "print(\"Qubits selected:\", best_qubits)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 79,
      "id": "12d3ac00-7dfc-4734-9881-4e6385f2d880",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/12d3ac00-7dfc-4734-9881-4e6385f2d880-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 79,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qubit_color = []\n",
        "for i in range(133):\n",
        "    if i in bad_readout_qubits:\n",
        "        qubit_color.append(\"#000000\")\n",
        "    elif i in best_qubits:\n",
        "        qubit_color.append(\"#ff00dd\")\n",
        "    else:\n",
        "        qubit_color.append(\"#8c00ff\")\n",
        "line_color = []\n",
        "for e in backend.target.build_coupling_map().get_edges():\n",
        "    if e in bad_ecrgate_edges:\n",
        "        line_color.append(\"#ffffff\")\n",
        "    else:\n",
        "        line_color.append(\"#888888\")\n",
        "plot_gate_map(\n",
        "    backend,\n",
        "    qubit_color=qubit_color,\n",
        "    line_color=line_color,\n",
        "    qubit_size=50,\n",
        "    font_size=25,\n",
        "    figsize=(6, 6),\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 80,
      "id": "6afd6c54-b427-4f34-8c4c-285c0122aebd",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/6afd6c54-b427-4f34-8c4c-285c0122aebd-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 80,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from rustworkx.visualization import graphviz_draw\n",
        "\n",
        "tree = rx.PyDiGraph()\n",
        "tree.extend_from_weighted_edge_list(vis.edges)\n",
        "tree.remove_nodes_from([n for n in range(max(best_qubits) + 1) if n not in best_qubits])\n",
        "\n",
        "graphviz_draw(tree, method=\"dot\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "70b0b915-478e-4d65-9840-fb3db3e0fd0e",
      "metadata": {},
      "source": [
        "A profundidade dessa árvore é 5.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 81,
      "id": "d36cdb58-59fe-474e-9a31-a2d9e806ab59",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/d36cdb58-59fe-474e-9a31-a2d9e806ab59-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 81,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz3 = QuantumCircuit(max(best_qubits) + 1, N)\n",
        "\n",
        "ghz3.h(tree.edge_list()[0][0])  # apply H-gate to the root node\n",
        "# Apply CNOT from the root node to the each edge.\n",
        "for u, v in tree.edge_list():\n",
        "    ghz3.cx(u, v)\n",
        "ghz3.barrier()  # for visualization\n",
        "ghz3.measure(best_qubits, list(range(N)))\n",
        "ghz3.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 82,
      "id": "1b1dfb32-bcbf-4107-80df-4b36c166b88b",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "11"
            ]
          },
          "execution_count": 82,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz3.depth()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 83,
      "id": "46df385d-dd28-4fab-8344-6ef2fd53906d",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/46df385d-dd28-4fab-8344-6ef2fd53906d-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 83,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm = generate_preset_pass_manager(1, backend=backend)\n",
        "ghz3_transpiled = pm.run(ghz3)\n",
        "ghz3_transpiled.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 84,
      "id": "74af05ba-132e-480d-ac5d-7b3bb4f4f0e4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Depth: 31\n",
            "Two-qubit Depth: 9\n"
          ]
        }
      ],
      "source": [
        "print(\"Depth:\", ghz3_transpiled.depth())\n",
        "print(\n",
        "    \"Two-qubit Depth:\",\n",
        "    ghz3_transpiled.depth(filter_function=lambda x: x.operation.num_qubits == 2),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fb74efcc-9db1-49b0-9f53-f5de236c6f29",
      "metadata": {},
      "source": [
        "<span id=\"32-select-a-different-root-node-manually\" />\n",
        "\n",
        "### 3.2 Selecione manualmente um nó raiz diferente\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 85,
      "id": "fb72a71a-8176-4b62-ac51-5a75469f0256",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Qubits selected: [23, 24, 25, 34, 35, 42, 43, 44, 45, 46, 47, 48, 49, 50, 54, 55, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 73, 84, 85, 86]\n"
          ]
        }
      ],
      "source": [
        "central = 54\n",
        "\n",
        "vis = TreeEdgesRecorder(N)\n",
        "rx.bfs_search(g, [central], vis)\n",
        "best_qubits = sorted(list(set(q for e in vis.edges for q in (e[0], e[1]))))\n",
        "print(\"Qubits selected:\", best_qubits)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 86,
      "id": "5e2e2af5-34b5-4bb5-b393-18e87d56db08",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/5e2e2af5-34b5-4bb5-b393-18e87d56db08-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 86,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from rustworkx.visualization import graphviz_draw\n",
        "\n",
        "tree = rx.PyDiGraph()\n",
        "tree.extend_from_weighted_edge_list(vis.edges)\n",
        "tree.remove_nodes_from([n for n in range(max(best_qubits) + 1) if n not in best_qubits])\n",
        "\n",
        "graphviz_draw(tree, method=\"dot\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0c481352-267a-4a34-85aa-32149bc4674a",
      "metadata": {},
      "source": [
        "A profundidade dessa árvore é de 6.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 87,
      "id": "5d81d890-a939-455f-81a6-c7e671671ba5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/5d81d890-a939-455f-81a6-c7e671671ba5-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 87,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz3 = QuantumCircuit(max(best_qubits) + 1, N)\n",
        "\n",
        "ghz3.h(tree.edge_list()[0][0])  # apply H-gate to the root node\n",
        "# Apply CNOT from the root node to the each edge.\n",
        "for u, v in tree.edge_list():\n",
        "    ghz3.cx(u, v)\n",
        "ghz3.barrier()  # for visualization\n",
        "ghz3.measure(best_qubits, list(range(N)))\n",
        "ghz3.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 88,
      "id": "b3ae6f53-c321-4a31-b4c7-8dea94267503",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "11"
            ]
          },
          "execution_count": 88,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz3.depth()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 89,
      "id": "b9823b6d-a658-40ef-a509-f03e33534af6",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/b9823b6d-a658-40ef-a509-f03e33534af6-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 89,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm = generate_preset_pass_manager(1, backend=backend)\n",
        "ghz3_transpiled = pm.run(ghz3)\n",
        "ghz3_transpiled.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 90,
      "id": "57a59793-c96b-4286-9ffc-76a3861f454c",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Depth: 30\n",
            "Two-qubit Depth: 9\n"
          ]
        }
      ],
      "source": [
        "print(\"Depth:\", ghz3_transpiled.depth())\n",
        "print(\n",
        "    \"Two-qubit Depth:\",\n",
        "    ghz3_transpiled.depth(filter_function=lambda x: x.operation.num_qubits == 2),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1b80ecf5-2bc0-4fc4-835e-e4cf40bcf9d9",
      "metadata": {},
      "source": [
        "Surpreendentemente, enquanto a profundidade da árvore aumentou de 5 para 6, a profundidade de dois qubits diminuiu de 9 para 8! Portanto, vamos usar o último circuito.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7046ce9c-cce8-4fca-9875-f9ef78ccc488",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-on-target-hardware\" />\n",
        "\n",
        "#### Etapa 3: Executar no hardware de destino\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "4ca22249-5efa-4ea1-a88e-f89d3235260b",
      "metadata": {},
      "outputs": [],
      "source": [
        "res = execute_ghz_fidelity(\n",
        "    ghz_circuit=ghz3,\n",
        "    physical_qubits=best_qubits,\n",
        "    backend=backend,\n",
        "    sampler_options=opts,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 95,
      "id": "bfbabf7e-421c-4ccd-8dfd-ec8cf5c14ebc",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "DONE DONE\n"
          ]
        }
      ],
      "source": [
        "job_s = service.job(res[0])  # Use your job id showed above.\n",
        "job_e = service.job(res[1])\n",
        "print(job_s.status(), job_e.status())"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7615f4df-9efe-435a-9521-356041db7b8f",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-results\" />\n",
        "\n",
        "#### Etapa 4: Resultados pós-processamento\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 96,
      "id": "670788ad-a209-4d0d-9b6d-9961b8d06900",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "N=30: |00..0>: 4, |11..1>: 218, |3rd>: 265 (111111111111111011111111111111)\n",
            "P(|00..0>)=0.0001, P(|11..1>)=0.00545\n",
            "REM: Coherence (non-diagonal): 0.187073\n",
            "GHZ fidelity = 0.096312 ± 0.003254\n",
            "GME (genuinely multipartite entangled) test: Failed\n"
          ]
        }
      ],
      "source": [
        "N = 30\n",
        "# Check fidelity from job IDs\n",
        "res = check_ghz_fidelity_from_jobs(\n",
        "    sampler_job=job_s,\n",
        "    estimator_job=job_e,\n",
        "    num_qubits=N,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6eb15797-36a9-4844-b7ec-14a607f6a784",
      "metadata": {},
      "source": [
        "Como você pode ver, esse resultado não atendeu aos critérios.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 97,
      "id": "66c87870",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/66c87870-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 97,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# It will take some time\n",
        "result = job_s.result()\n",
        "plot_histogram(result[0].data.c.get_counts(), figsize=(30, 5))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "43a2f073-b19c-46b4-a7b4-40d2c705c3b7",
      "metadata": {},
      "source": [
        "<span id=\"4-strategy-3-run-with-the-error-suppression-options\" />\n",
        "\n",
        "## 4. Estratégia 3. Execute com as opções de supressão de erros\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2c40dc0f-93a0-4fae-980f-b7c5ab449a40",
      "metadata": {},
      "source": [
        "Você pode definir as opções de supressão de erros no Sampler V2. Consulte o guia [de gerenciamento de ruído do Sampler](/docs/guides/sampler-noise-management) e a [`ExecutionOptionsV2`](/docs/api/qiskit-ibm-runtime/options-execution-options-v2) referência da API para obter mais informações.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 98,
      "id": "04f91676-6218-4875-bc44-5281b83a0718",
      "metadata": {},
      "outputs": [],
      "source": [
        "opts = SamplerOptions()\n",
        "opts.dynamical_decoupling.enable = True\n",
        "opts.execution.rep_delay = 0.0005\n",
        "opts.twirling.enable_gates = True"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8e630f61-ae43-46ee-85d6-daf0cd89f94d",
      "metadata": {},
      "outputs": [],
      "source": [
        "res = execute_ghz_fidelity(\n",
        "    ghz_circuit=ghz3,\n",
        "    physical_qubits=best_qubits,\n",
        "    backend=backend,\n",
        "    sampler_options=opts,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 105,
      "id": "42b659d3-e003-45d4-b460-8a3db6995e34",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "DONE DONE\n"
          ]
        }
      ],
      "source": [
        "job_s = service.job(res[0])  # Use your job id showed above.\n",
        "job_e = service.job(res[1])\n",
        "print(job_s.status(), job_e.status())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 106,
      "id": "bf3cc6a7-4d02-4f90-a411-57fc2eac0513",
      "metadata": {},
      "outputs": [],
      "source": [
        "N = 30"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 107,
      "id": "1faa3e59-386e-47e3-ae96-101ecb3c08df",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "N=30: |00..0>: 1459, |11..1>: 1543, |3rd>: 359 (111111111111111111111111111110)\n",
            "P(|00..0>)=0.036475, P(|11..1>)=0.038575\n",
            "REM: Coherence (non-diagonal): 0.165532\n",
            "GHZ fidelity = 0.120291 ± 0.003369\n",
            "GME (genuinely multipartite entangled) test: Failed\n"
          ]
        }
      ],
      "source": [
        "# Check fidelity from job IDs\n",
        "res = check_ghz_fidelity_from_jobs(\n",
        "    sampler_job=job_s,\n",
        "    estimator_job=job_e,\n",
        "    num_qubits=N,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 108,
      "id": "166856be-ad3a-40d6-837c-3eedda374891",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/166856be-ad3a-40d6-837c-3eedda374891-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 108,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# It will take some time\n",
        "result = job_s.result()\n",
        "plot_histogram(result[0].data.c.get_counts(), figsize=(30, 5))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c8547268-3604-4fe9-b52c-f48f0d036647",
      "metadata": {},
      "source": [
        "O resultado melhorou, mas ainda não atendeu aos critérios.\n",
        "\n",
        "Vimos três ideias até agora. Você pode combinar e expandir essas ideias ou ter suas próprias ideias para criar um circuito GHZ melhor. Agora vamos rever o objetivo novamente.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "70b460c8",
      "metadata": {},
      "source": [
        "<span id=\"5-your-goal-recap\" />\n",
        "\n",
        "## 5. Seu objetivo (recapitulação)\n",
        "\n",
        "Construa um circuito GHZ para 20 qubits ou mais, de modo que o resultado da medição atenda aos critérios: A fidelidade de seu estado GHZ > 0.5.\n",
        "\n",
        "* Você precisa usar um dispositivo Eagle (como `ibm_brisbane`) e definir o número de disparos como 40.000.\n",
        "* Você deve executar o circuito GHZ usando a função `execute_ghz_fidelity` e calcular a fidelidade usando a função `check_ghz_fidelity_from_jobs` .\n",
        "  Você precisa encontrar os maiores qubits - circuito GHZ que atendam aos critérios. Escreva seu código abaixo e mostre o resultado com a função `check_ghz_fidelity_from_jobs` .\n",
        "\n",
        "Agora implementamos o mesmo fluxo de trabalho GHZ do material anterior, mas em um dispositivo Heron. Isso lhe dá alguma experiência com o layout e os recursos dos processadores Heron. Não são introduzidas novas estratégias.\n",
        "\n",
        "*O tempo aproximado da QPU para executar o próximo experimento é de 4 m 40 s.*\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "2db80d2a-1c87-4d94-a2d5-17db3fddbb96",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Device ibm_kingston Loaded with 156 qubits\n",
            "Two Qubit Gate: cz\n"
          ]
        }
      ],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.backend(\"ibm_kingston\")\n",
        "# backend = service.backend(\"ibm_fez\")\n",
        "\n",
        "twoq_gate = \"cz\"\n",
        "print(f\"Device {backend.name} Loaded with {backend.num_qubits} qubits\")\n",
        "print(f\"Two Qubit Gate: {twoq_gate}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 141,
      "id": "5490bc61-0f0d-411b-b9bc-53d68ff2f877",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Bad readout qubits: [112, 113, 120, 131, 146]\n",
            "Bad CZ gates: [(111, 112), (112, 111), (112, 113), (113, 112), (120, 121), (121, 120), (130, 131), (131, 130), (145, 146), (146, 145), (146, 147), (147, 146)]\n"
          ]
        }
      ],
      "source": [
        "BAD_READOUT_ERROR_THRESHOLD = 0.1\n",
        "BAD_CZGATE_ERROR_THRESHOLD = 0.1\n",
        "bad_readout_qubits = [\n",
        "    q\n",
        "    for q in range(backend.num_qubits)\n",
        "    if backend.target[\"measure\"][(q,)].error > BAD_READOUT_ERROR_THRESHOLD\n",
        "]\n",
        "bad_czgate_edges = [\n",
        "    qpair\n",
        "    for qpair in backend.target[\"cz\"]\n",
        "    if backend.target[\"cz\"][qpair].error > BAD_CZGATE_ERROR_THRESHOLD\n",
        "]\n",
        "print(\"Bad readout qubits:\", bad_readout_qubits)\n",
        "print(\"Bad CZ gates:\", bad_czgate_edges)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 142,
      "id": "71df32ed-4b7c-4a7a-8fcf-bd508478b6ad",
      "metadata": {},
      "outputs": [],
      "source": [
        "g = backend.coupling_map.graph.copy().to_undirected()\n",
        "g.remove_edges_from(\n",
        "    bad_czgate_edges\n",
        ")  # remove edge first (otherwise might fail with a NoEdgeBetweenNodes error)\n",
        "g.remove_nodes_from(bad_readout_qubits)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 145,
      "id": "e4336cf4-95e6-41a2-b24c-74d1cec53c36",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/e4336cf4-95e6-41a2-b24c-74d1cec53c36-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 145,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qubit_color = []\n",
        "for i in range(backend.num_qubits):\n",
        "    if i in bad_readout_qubits:\n",
        "        qubit_color.append(\"#000000\")  # black\n",
        "    else:\n",
        "        qubit_color.append(\"#8c00ff\")  # purple\n",
        "line_color = []\n",
        "for e in backend.target.build_coupling_map().get_edges():\n",
        "    if e in bad_czgate_edges:\n",
        "        line_color.append(\"#ffffff\")  # white\n",
        "    else:\n",
        "        line_color.append(\"#888888\")  # gray\n",
        "plot_gate_map(\n",
        "    backend,\n",
        "    qubit_color=qubit_color,\n",
        "    line_color=line_color,\n",
        "    qubit_size=60,\n",
        "    font_size=30,\n",
        "    figsize=(10, 10),\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 146,
      "id": "5afaf902-a59f-4ae9-b4fb-95b9d861676e",
      "metadata": {},
      "outputs": [],
      "source": [
        "N = 40\n",
        "central = 100  # Select the center node manually\n",
        "# c_degree = dict(rx.betweenness_centrality(g))\n",
        "# central = max(c_degree, key=c_degree.get)\n",
        "# central"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 147,
      "id": "24bf4ea2-dd6f-442e-a989-5c8b29e93847",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Qubits selected: [61, 65, 76, 77, 80, 81, 82, 83, 84, 85, 86, 87, 96, 97, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 116, 117, 121, 122, 123, 124, 125, 126, 127, 136, 140, 141, 142, 143, 144, 145]\n"
          ]
        }
      ],
      "source": [
        "class TreeEdgesRecorder(rx.visit.BFSVisitor):\n",
        "    def __init__(self, N):\n",
        "        self.edges = []\n",
        "        self.N = N\n",
        "\n",
        "    def tree_edge(self, edge):\n",
        "        self.edges.append(edge)\n",
        "        if len(self.edges) >= self.N - 1:\n",
        "            raise rx.visit.StopSearch()\n",
        "\n",
        "\n",
        "vis = TreeEdgesRecorder(N)\n",
        "rx.bfs_search(g, [central], vis)\n",
        "best_qubits = sorted(list(set(q for e in vis.edges for q in (e[0], e[1]))))\n",
        "print(\"Qubits selected:\", best_qubits)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 149,
      "id": "e684af6c-aa99-460d-b0f5-9d5042fb80b0",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/e684af6c-aa99-460d-b0f5-9d5042fb80b0-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 149,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qubit_color = []\n",
        "for i in range(backend.num_qubits):\n",
        "    if i in bad_readout_qubits:\n",
        "        qubit_color.append(\"#000000\")\n",
        "    elif i in best_qubits:\n",
        "        qubit_color.append(\"#ff00dd\")\n",
        "    else:\n",
        "        qubit_color.append(\"#8c00ff\")\n",
        "line_color = []\n",
        "for e in backend.target.build_coupling_map().get_edges():\n",
        "    if e in bad_czgate_edges:\n",
        "        line_color.append(\"#ffffff\")\n",
        "    else:\n",
        "        line_color.append(\"#888888\")\n",
        "plot_gate_map(\n",
        "    backend,\n",
        "    qubit_color=qubit_color,\n",
        "    line_color=line_color,\n",
        "    qubit_size=60,\n",
        "    font_size=30,\n",
        "    figsize=(10, 10),\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 150,
      "id": "f3ff2dd9-a304-409c-a0e4-3b23e85f282e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/f3ff2dd9-a304-409c-a0e4-3b23e85f282e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 150,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from rustworkx.visualization import graphviz_draw\n",
        "\n",
        "tree = rx.PyDiGraph()\n",
        "tree.extend_from_weighted_edge_list(vis.edges)\n",
        "tree.remove_nodes_from([n for n in range(max(best_qubits) + 1) if n not in best_qubits])\n",
        "\n",
        "graphviz_draw(tree, method=\"dot\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 151,
      "id": "60b6526c-55ed-4621-b91b-4ceeef34de62",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/60b6526c-55ed-4621-b91b-4ceeef34de62-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 151,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz_h = QuantumCircuit(max(best_qubits) + 1, N)\n",
        "\n",
        "ghz_h.h(tree.edge_list()[0][0])  # apply H-gate to the root node\n",
        "# Apply CNOT from the root node to the each edge.\n",
        "for u, v in tree.edge_list():\n",
        "    ghz_h.cx(u, v)\n",
        "ghz_h.barrier()  # for visualization\n",
        "ghz_h.measure(best_qubits, list(range(N)))\n",
        "ghz_h.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 152,
      "id": "1365cbef-f587-4a34-9d68-5f1d9afc0f43",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "15"
            ]
          },
          "execution_count": 152,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz_h.depth()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 153,
      "id": "b96e6342-e08b-4728-8985-7a015ee16797",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/b96e6342-e08b-4728-8985-7a015ee16797-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 153,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm = generate_preset_pass_manager(1, backend=backend)\n",
        "ghz_h_transpiled = pm.run(ghz_h)\n",
        "ghz_h_transpiled.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 154,
      "id": "614a2f14-aff8-4942-8709-9a40c5e041d9",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Depth: 45\n",
            "Two-qubit Depth: 13\n"
          ]
        }
      ],
      "source": [
        "print(\"Depth:\", ghz_h_transpiled.depth())\n",
        "print(\n",
        "    \"Two-qubit Depth:\",\n",
        "    ghz_h_transpiled.depth(filter_function=lambda x: x.operation.num_qubits == 2),\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 155,
      "id": "da2e2f98-b79b-42bd-8fbd-3ccb824c6729",
      "metadata": {},
      "outputs": [],
      "source": [
        "opts = SamplerOptions()\n",
        "opts.dynamical_decoupling.enable = True\n",
        "opts.execution.rep_delay = 0.0005\n",
        "opts.twirling.enable_gates = True"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "0d659b1b-fe1a-4e42-ac8c-08b05514590b",
      "metadata": {},
      "outputs": [],
      "source": [
        "res = execute_ghz_fidelity(\n",
        "    ghz_circuit=ghz_h,\n",
        "    physical_qubits=best_qubits,\n",
        "    backend=backend,\n",
        "    sampler_options=opts,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 174,
      "id": "0162d22f-899c-4fed-86b8-dbb45673c2c0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "RUNNING RUNNING\n"
          ]
        }
      ],
      "source": [
        "job_s = service.job(res[0])  # Use your job id showed above.\n",
        "job_e = service.job(res[1])\n",
        "print(job_s.status(), job_e.status())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 170,
      "id": "c6d1bad8-381c-4ba9-be2f-b1575741af53",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "N=40: |00..0>: 3186, |11..1>: 3277, |3rd>: 620 (1111111011111111111111111111111111111111)\n",
            "P(|00..0>)=0.07965, P(|11..1>)=0.081925\n",
            "REM: Coherence (non-diagonal): 0.029987\n",
            "GHZ fidelity = 0.095781 ± 0.002619\n",
            "GME (genuinely multipartite entangled) test: Failed\n"
          ]
        }
      ],
      "source": [
        "# Check fidelity from job IDs\n",
        "N = 40\n",
        "res = check_ghz_fidelity_from_jobs(\n",
        "    sampler_job=job_s,\n",
        "    estimator_job=job_e,\n",
        "    num_qubits=N,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 171,
      "id": "671f57ea-7117-4d17-998f-73baa6f4463e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/671f57ea-7117-4d17-998f-73baa6f4463e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 171,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# It will take some time\n",
        "result = job_s.result()\n",
        "plot_histogram(result[0].data.c.get_counts(), figsize=(30, 5))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c817f572-1c67-4ed8-b466-ecdf5c41d88b",
      "metadata": {},
      "source": [
        "Parabéns! Você concluiu sua introdução à computação quântica em escala de serviços públicos! Agora você está pronto para fazer contribuições significativas na busca pela vantagem quântica! Obrigado por tornar o IBM Quantum® parte de sua jornada quântica pessoal.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1ddd145f",
      "metadata": {},
      "source": [
        "<span id=\"post-course-survey\" />\n",
        "\n",
        "## Pesquisa pós-curso\n",
        "\n",
        "Parabéns por ter concluído este curso! Reserve um momento para nos ajudar a melhorar nosso curso, preenchendo a [pesquisa rápida](https://your.feedback.ibm.com/jfe/form/SV_5vvmdT5yFFetkgK) a seguir. Seus comentários serão usados para aprimorar nossa oferta de conteúdo e a experiência do usuário. Agradecemos seu feedback!\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"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "state": {},
        "version_major": 2,
        "version_minor": 0
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}