{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "eb16d89d-f6fc-417f-9ce5-19251d039df7",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Corte de circuito para condições de contorno periódicas\"\n",
        "description: \"Use o corte de circuito para lidar com um problema de cadeia periódica em escala utilitária, em que o primeiro e o último qubits não são vizinhos.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore fontsize edgecolor */}\n",
        "\n",
        "<span id=\"circuit-cutting-for-periodic-boundary-conditions\" />\n",
        "\n",
        "# Corte de circuito para condições de contorno periódicas\n",
        "\n",
        "*Estimativa de uso: Dois minutos em um processador Eagle (OBSERVAÇÃO: esta é apenas uma estimativa. Seu tempo de execução pode variar)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f053a0b1",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## Segundo plano\n",
        "\n",
        "Neste caderno, consideramos a simulação de uma cadeia periódica de qubits em que há duas operações de qubit entre cada dois qubits adjacentes, incluindo o primeiro e o último. As cadeias periódicas são frequentemente encontradas em problemas de física e química, como modelos de Ising e simulação molecular.\n",
        "\n",
        "Os dispositivos IBM Quantum® atuais são planares. É possível incorporar algumas cadeias periódicas na topologia diretamente onde o primeiro e o último qubits são vizinhos. No entanto, para problemas grandes o suficiente, o primeiro e o último qubits podem estar distantes, exigindo assim muitas portas SWAP para a operação de 2 qubits entre esses dois qubits. Esse problema de limite periódico foi estudado em <a href=\"https://arxiv.org/abs/2402.17833\">este documento</a>.\n",
        "\n",
        "Neste caderno, mostramos o uso do corte de circuitos para lidar com esse problema de cadeia periódica em escala de utilidade em que o primeiro e o último qubits não são vizinhos. O corte dessa conectividade de longo alcance evita os portões SWAP extras ao custo da execução de várias instâncias do circuito e de algum pós-processamento clássico. Em resumo, o corte pode ser incorporado para calcular logicamente as operações de 2 qubits de longa distância. Em outras palavras, essa abordagem leva a um aumento efetivo na conectividade do mapa de acoplamento, resultando em um número menor de portas SWAP.\n",
        "\n",
        "Observe que há dois tipos de cortes - cortar o fio de um circuito (chamado `wire cutting`) ou substituir uma porta de 2 qubits por várias operações de um único qubit (chamado `gate cutting`). Neste caderno, vamos nos concentrar no corte de porta. Para obter mais detalhes sobre o corte de portões, consulte o site <a href=\"https://qiskit.github.io/qiskit-addon-cutting/explanation/index.html\">materiais explicativos</a> em `qiskit-addon-cutting` e as referências correspondentes. Para obter mais detalhes sobre o corte de fios, consulte o tutorial [Corte de fios para estimativa de valores de expectativa](/docs/tutorials/wire-cutting) ou os tutoriais em <a href=\"https://qiskit.github.io/qiskit-addon-cutting/tutorials/index.html\">qiskit-addon-cutting</a>.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "120312e5-0eed-4168-9098-633a3d0e6e57",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## Requisitos\n",
        "\n",
        "Antes de iniciar este tutorial, verifique se você tem os seguintes itens instalados:\n",
        "\n",
        "* Qiskit SDK v1.2 ou mais tarde (`pip install qiskit`)\n",
        "* Qiskit Runtime v0.3 ou mais tarde (`pip install qiskit-ibm-runtime`)\n",
        "* Complemento Qiskit para corte de circuitos v.9.0 ou posterior (`pip install qiskit-addon-cutting`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f0af3c7d",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## Instalação\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f01e3062",
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "import matplotlib as mpl\n",
        "\n",
        "from qiskit.transpiler import PassManager\n",
        "from qiskit.transpiler.passes import (\n",
        "    BasisTranslator,\n",
        "    Optimize1qGatesDecomposition,\n",
        ")\n",
        "from qiskit.circuit.equivalence_library import (\n",
        "    SessionEquivalenceLibrary as sel,\n",
        ")\n",
        "from qiskit.converters import circuit_to_dag, dag_to_circuit\n",
        "from qiskit.result import sampled_expectation_value\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "from qiskit.circuit.library import TwoLocal\n",
        "\n",
        "from qiskit_addon_cutting import (\n",
        "    cut_gates,\n",
        "    generate_cutting_experiments,\n",
        "    reconstruct_expectation_values,\n",
        ")\n",
        "\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime import SamplerV2, SamplerOptions, Batch"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6e7c685c-3e10-4cf1-a435-2b0fc761ebc4",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "## Passo 1: Mapear entradas clássicas para um problema quântico\n",
        "\n",
        "Aqui, geraremos um circuito TwoLocal e definiremos alguns observáveis.\n",
        "\n",
        "<ul>\n",
        "  <li>Entrada: Parâmetros para criar um circuito</li>\n",
        "  <li>Saída: Circuito abstrato e observáveis</li>\n",
        "</ul>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8590c112-cf8a-4bc3-ab8b-411d1a1b010a",
      "metadata": {},
      "source": [
        "Consideramos um `entangler map` eficiente em termos de hardware para o circuito TwoLocal com conectividade periódica entre o último e o primeiro qubits do `entangler map`. Essa interação de longo alcance pode levar a portas SWAP adicionais durante a transpilação, aumentando assim a profundidade do circuito.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0776185d-4ea8-4a8c-ab14-121636444d8f",
      "metadata": {},
      "source": [
        "<span id=\"select-backend-and-initial-layout\" />\n",
        "\n",
        "#### Selecione o backend e o layout inicial\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "81c616a7-248a-412b-bac5-080eb9199760",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "15b9c4e5-7b25-4b95-9d79-bf73b9adad97",
      "metadata": {},
      "source": [
        "Para este notebook, consideraremos uma cadeia 1D periódica de 109 qubits, que é a cadeia 1D mais longa na topologia de um dispositivo IBM Quantum de 127 qubits. Não é possível organizar uma cadeia periódica de 109 qubits em um dispositivo de 127 qubits de modo que o primeiro e o último qubits sejam vizinhos sem incorporar portas SWAP adicionais.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "6f8c4588-0532-41f9-9d6d-50e754466593",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "109"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "init_layout = [\n",
        "    13,\n",
        "    12,\n",
        "    11,\n",
        "    10,\n",
        "    9,\n",
        "    8,\n",
        "    7,\n",
        "    6,\n",
        "    5,\n",
        "    4,\n",
        "    3,\n",
        "    2,\n",
        "    1,\n",
        "    0,\n",
        "    14,\n",
        "    18,\n",
        "    19,\n",
        "    20,\n",
        "    21,\n",
        "    22,\n",
        "    23,\n",
        "    24,\n",
        "    25,\n",
        "    26,\n",
        "    27,\n",
        "    28,\n",
        "    29,\n",
        "    30,\n",
        "    31,\n",
        "    32,\n",
        "    36,\n",
        "    51,\n",
        "    50,\n",
        "    49,\n",
        "    48,\n",
        "    47,\n",
        "    46,\n",
        "    45,\n",
        "    44,\n",
        "    43,\n",
        "    42,\n",
        "    41,\n",
        "    40,\n",
        "    39,\n",
        "    38,\n",
        "    37,\n",
        "    52,\n",
        "    56,\n",
        "    57,\n",
        "    58,\n",
        "    59,\n",
        "    60,\n",
        "    61,\n",
        "    62,\n",
        "    63,\n",
        "    64,\n",
        "    65,\n",
        "    66,\n",
        "    67,\n",
        "    68,\n",
        "    69,\n",
        "    70,\n",
        "    74,\n",
        "    89,\n",
        "    88,\n",
        "    87,\n",
        "    86,\n",
        "    85,\n",
        "    84,\n",
        "    83,\n",
        "    82,\n",
        "    81,\n",
        "    80,\n",
        "    79,\n",
        "    78,\n",
        "    77,\n",
        "    76,\n",
        "    75,\n",
        "    90,\n",
        "    94,\n",
        "    95,\n",
        "    96,\n",
        "    97,\n",
        "    98,\n",
        "    99,\n",
        "    100,\n",
        "    101,\n",
        "    102,\n",
        "    103,\n",
        "    104,\n",
        "    105,\n",
        "    106,\n",
        "    107,\n",
        "    108,\n",
        "    112,\n",
        "    126,\n",
        "    125,\n",
        "    124,\n",
        "    123,\n",
        "    122,\n",
        "    121,\n",
        "    120,\n",
        "    119,\n",
        "    118,\n",
        "    117,\n",
        "    116,\n",
        "    115,\n",
        "    114,\n",
        "    113,\n",
        "]\n",
        "\n",
        "# the number of qubits in the circuit is governed by the length of the initial layout\n",
        "num_qubits = len(init_layout)\n",
        "num_qubits"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "da94a31f-3bce-40e5-a580-b938ff255425",
      "metadata": {},
      "source": [
        "<span id=\"build-the-entangler-map-for-the-twolocal-circuit\" />\n",
        "\n",
        "#### Construa o mapa do entrelaçador para o circuito TwoLocal\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "15bc3ac1-dbb6-4bb5-8d3e-63f3638f7a96",
      "metadata": {},
      "outputs": [],
      "source": [
        "coupling_map = [(i, i + 1) for i in range(0, len(init_layout) - 1)]\n",
        "coupling_map.append(\n",
        "    (len(init_layout) - 1, 0)\n",
        ")  # adding in the periodic connectivity"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b7b4970f-ac13-4644-a92f-1796de876767",
      "metadata": {},
      "source": [
        "TwoLocal o circuito permite a repetição do `rotation_blocks` e do `entangler map` várias vezes. Nesse caso, o número de repetições determina o número de portas periódicas que precisam ser cortadas. Como a sobrecarga de amostragem aumenta exponencialmente com o número de cortes (consulte o tutorial [Wire cutting for expectation values estimation](/docs/tutorials/wire-cutting) para obter mais detalhes), vamos fixar o número de repetições em 2 neste notebook.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "0cd786ff-9798-4e20-937f-a258eea88077",
      "metadata": {},
      "outputs": [],
      "source": [
        "num_reps = 2\n",
        "entangler_map = []\n",
        "\n",
        "for even_edge in coupling_map[0 : len(coupling_map) : 2]:\n",
        "    entangler_map.append(even_edge)\n",
        "\n",
        "for odd_edge in coupling_map[1 : len(coupling_map) : 2]:\n",
        "    entangler_map.append(odd_edge)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "79428537-66cf-40ce-87cf-0f75f591cb4b",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/periodic-boundary-conditions-with-circuit-cutting/extracted-outputs/79428537-66cf-40ce-87cf-0f75f591cb4b-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ansatz = TwoLocal(\n",
        "    num_qubits=num_qubits,\n",
        "    rotation_blocks=\"rx\",\n",
        "    entanglement_blocks=\"cx\",\n",
        "    entanglement=entangler_map,\n",
        "    reps=num_reps,\n",
        ").decompose()\n",
        "ansatz.draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "18b2f9b3-07f0-47d0-88db-7182e03c5f53",
      "metadata": {},
      "source": [
        "Para verificar a qualidade do resultado usando o corte de circuitos, precisamos conhecer o resultado ideal. O circuito atual escolhido está além da simulação clássica de força bruta. Portanto, fixamos os parâmetros do circuito cuidadosamente para torná-lo clifford.\n",
        "\n",
        "Atribuiremos o valor do parâmetro $0$ para as duas primeiras camadas de portas `Rx` e o valor $\\pi$ para a última camada. Isso garante que o resultado ideal desse circuito seja $|1\\rangle^{\\otimes n}$, sendo $n$ o número de qubits. Portanto, os valores de expectativa de $\\langle Z_i \\rangle$ e $\\langle Z_i Z_{i+1} \\rangle$, em que $i$ é o índice do qubit, são $-1$ e $+1$, respectivamente.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a0d70827-ae61-49a0-b14c-c10b27963262",
      "metadata": {},
      "outputs": [],
      "source": [
        "params_last_layer = [np.pi] * ansatz.num_qubits\n",
        "params = [0] * (ansatz.num_parameters - ansatz.num_qubits)\n",
        "params.extend(params_last_layer)\n",
        "\n",
        "ansatz.assign_parameters(params, inplace=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8f4289dd-30fd-4295-9d33-488f2fc03a3a",
      "metadata": {},
      "source": [
        "<span id=\"select-observables\" />\n",
        "\n",
        "#### Selecione observáveis\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6a359888-c685-4b28-b2d4-c29b89448e3b",
      "metadata": {},
      "source": [
        "Para quantificar os benefícios do corte de porta, medimos os valores de expectativa dos observáveis $\\frac{1}{n}\\sum_{i=1}^n \\langle Z_i \\rangle$ e $\\frac{1}{n-1}\\sum_{i=1}^{n-1} \\langle Z_i Z_{i+1} \\rangle$. Conforme discutido anteriormente, os valores de expectativa ideais são $-1$ e $+1$, respectivamente.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "87a6a367-2d4e-410c-8e5f-3ef069f968d8",
      "metadata": {},
      "outputs": [],
      "source": [
        "observables = []\n",
        "\n",
        "for i in range(num_qubits):\n",
        "    obs = \"I\" * (i) + \"Z\" + \"I\" * (num_qubits - i - 1)\n",
        "    observables.append(obs)\n",
        "\n",
        "for i in range(num_qubits):\n",
        "    if i == num_qubits - 1:\n",
        "        obs = \"Z\" + \"I\" * (num_qubits - 2) + \"Z\"\n",
        "    else:\n",
        "        obs = \"I\" * i + \"ZZ\" + \"I\" * (num_qubits - i - 2)\n",
        "    observables.append(obs)\n",
        "\n",
        "observables = SparsePauliOp(observables)\n",
        "paulis = observables.paulis\n",
        "coeffs = observables.coeffs"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "906440c1-4e5b-4f18-9bc7-d450dd7d2b24",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "## Etapa 2: Otimizar o problema para execução em hardware quântico\n",
        "\n",
        "<ul>\n",
        "  <li>Entrada: Circuito abstrato e observáveis</li>\n",
        "  <li>Saída: Circuito-alvo e observáveis produzidos pelo corte de portas de longo alcance</li>\n",
        "</ul>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2a7387e5-ead4-4dd8-a01f-974138cda3d9",
      "metadata": {},
      "source": [
        "<span id=\"transpile-the-circuit\" />\n",
        "\n",
        "#### Transpilar o circuito\n",
        "\n",
        "Observe que o circuito pode ser transpilado nesse estágio ou após o corte. Se fizermos a transpilação após o corte, será necessário fazer a transpilação de cada um dos subexperimentos gerados devido à sobrecarga de amostragem. Portanto, é mais prudente transpilar nesse estágio para reduzir a sobrecarga da transpilação.\n",
        "\n",
        "No entanto, se a transpilação for feita nesse estágio com conectividade de hardware nativa, o transpilador anexará várias portas SWAP para colocar a operação periódica de 2 qubits, ofuscando os benefícios do corte do circuito. Para evitar esse problema, podemos aproveitar o fato de conhecermos os portões exatos que precisam ser cortados. Especificamente, podemos criar um mapa de acoplamento virtual adicionando conexões virtuais entre qubits distantes para acomodar essas portas periódicas de 2 qubits. Isso garantirá que o circuito possa ser transpilado nesse estágio sem incorporar as portas SWAP adicionais.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "c12bb07e-54a0-4597-8b4d-4d0fbf6a4c99",
      "metadata": {},
      "outputs": [],
      "source": [
        "coupling_map = backend.configuration().coupling_map\n",
        "\n",
        "# create a virtual coupling map with long range connectivity\n",
        "virtual_coupling_map = coupling_map.copy()\n",
        "virtual_coupling_map.append([init_layout[-1], init_layout[0]])\n",
        "virtual_coupling_map.append([init_layout[0], init_layout[-1]])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "ad38aa32-4613-46c5-bf62-da332a1b9dfb",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/periodic-boundary-conditions-with-circuit-cutting/extracted-outputs/ad38aa32-4613-46c5-bf62-da332a1b9dfb-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm_virtual = generate_preset_pass_manager(\n",
        "    optimization_level=1,\n",
        "    coupling_map=virtual_coupling_map,\n",
        "    initial_layout=init_layout,\n",
        "    basis_gates=backend.configuration().basis_gates,\n",
        ")\n",
        "\n",
        "virtual_mapped_circuit = pm_virtual.run(ansatz)\n",
        "virtual_mapped_circuit.draw(\"mpl\", fold=-1, idle_wires=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ecb4ae6e-f9a5-4453-a8a3-1a5aaaf954da",
      "metadata": {},
      "source": [
        "<span id=\"cut-the-long-range-periodic-connectivities\" />\n",
        "\n",
        "#### Corte as conectividades periódicas de longo alcance\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c155eda9-ba08-4069-9962-ece21926f1db",
      "metadata": {},
      "source": [
        "Agora, cortamos as portas no circuito transpilado. Observe que as portas de 2 qubits que precisam ser cortadas são as que conectam o último e o primeiro qubits do layout.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "718ea31e-c8d8-4cf9-975b-fc0e77fb27c0",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Find the indices of the distant gates\n",
        "cut_indices = [\n",
        "    i\n",
        "    for i, instruction in enumerate(virtual_mapped_circuit.data)\n",
        "    if {virtual_mapped_circuit.find_bit(q)[0] for q in instruction.qubits}\n",
        "    == {init_layout[-1], init_layout[0]}\n",
        "]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c6091cb0-227d-454a-a2d8-7ba685b66121",
      "metadata": {},
      "source": [
        "Aplicaremos o layout do circuito transpilado ao observável.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "af57d942-5997-4920-91c6-295fbfef478d",
      "metadata": {},
      "outputs": [],
      "source": [
        "trans_observables = observables.apply_layout(virtual_mapped_circuit.layout)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6a9a20e4-b722-456d-885b-d68ead3d341e",
      "metadata": {},
      "source": [
        "Por fim, os subexperimentos são gerados por amostragem em diferentes bases de medição e preparação.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "981f111c-69e6-44c2-a297-c7df302cbc0e",
      "metadata": {},
      "outputs": [],
      "source": [
        "qpd_circuit, bases = cut_gates(virtual_mapped_circuit, cut_indices)\n",
        "subexperiments, coefficients = generate_cutting_experiments(\n",
        "    circuits=qpd_circuit,\n",
        "    observables=trans_observables.paulis,\n",
        "    num_samples=np.inf,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "60582298-52ae-4f10-b8c2-bc754cb6d24c",
      "metadata": {},
      "source": [
        "Observe que o corte das interações de longo alcance leva à execução de várias amostras do circuito que diferem nas bases de medição e preparação. Mais informações sobre isso podem ser encontradas em <a href=\"https://arxiv.org/abs/1909.07534\">Construção de uma porta virtual de dois qubits por meio da amostragem de operações de um único qubit</a> e <a href=\"https://arxiv.org/abs/2312.11638\">Circuitos de corte com vários unitários de dois qubits</a>.\n",
        "\n",
        "O número de portas periódicas a serem cortadas é igual ao número de repetições da camada `TwoLocal` , definida como `num_reps` acima. A sobrecarga de amostragem do corte do portão é 6. Portanto, o número total de subexperimentos será $6^{num\\_reps}$.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "be4a43b4-c035-4814-a486-45eb9fe23d86",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Number of subexperiments is 36 = 6**2\n"
          ]
        }
      ],
      "source": [
        "print(f\"Number of subexperiments is {len(subexperiments)} = 6**{num_reps}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "41a11eed-a8c0-4cce-b59d-ca49c54b52b1",
      "metadata": {},
      "source": [
        "<span id=\"transpile-the-subexperiments\" />\n",
        "\n",
        "#### Transpilar as subexperiências\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5772d662-c030-4de6-9be4-e90cd599b173",
      "metadata": {},
      "source": [
        "Nesse ponto, os subexperimentos contêm circuitos com algumas portas de 1 qubit que não estão no conjunto de portas da base. Isso ocorre porque os qubits cortados são medidos em bases diferentes, e as portas de rotação usadas para isso não pertencem necessariamente ao conjunto de portas de base. Por exemplo, a medição na base X implica a aplicação de uma porta Hadamard antes da medição usual na base Z. Mas Hadamard não faz parte do conjunto de portas de base.\n",
        "\n",
        "Em vez de aplicar todo o processo de transpilação em cada um dos circuitos nos subexperimentos, podemos usar passagens específicas de transpilação. Consulte <a href=\"/docs/api/qiskit/transpiler_passes\">esta documentação</a> para obter uma descrição detalhada de todas as passagens de transpilação disponíveis.\n",
        "\n",
        "Aplicaremos `BasisTranslator` e depois `Optimize1qGatesDecomposition` passes para garantir que todas as portas desses circuitos pertençam ao conjunto de portas da base. O uso dessas duas passagens é mais rápido do que todo o processo de transpilação, pois outras etapas, como roteamento e seleção do layout inicial, não são executadas novamente.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "9c6d074f-5e48-4adb-9f4f-c5b03c9f7e36",
      "metadata": {},
      "outputs": [],
      "source": [
        "pass_ = PassManager(\n",
        "    [Optimize1qGatesDecomposition(basis=backend.configuration().basis_gates)]\n",
        ")\n",
        "\n",
        "subexperiments = pass_.run(\n",
        "    [\n",
        "        dag_to_circuit(\n",
        "            BasisTranslator(sel, target_basis=backend.basis_gates).run(\n",
        "                circuit_to_dag(circ)\n",
        "            )\n",
        "        )\n",
        "        for circ in subexperiments\n",
        "    ]\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4c5c0c60-3caa-4bd6-80aa-f7dc412680bb",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "## Passo 3: Execute usando Qiskit primitives\n",
        "\n",
        "<ul>\n",
        "  <li>Entrada: Circuitos-alvo</li>\n",
        "  <li>Saída: Distribuições de quase-probabilidade</li>\n",
        "</ul>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1fb3b96c-e55c-40e4-a5ca-4c327a192d73",
      "metadata": {},
      "source": [
        "Usamos a primitiva `SamplerV2` para a execução dos circuitos de corte. Desativamos `dynamical decoupling` e `twirling` para que qualquer melhoria que obtivermos no resultado se deva exclusivamente à aplicação efetiva do corte de porta para esse tipo de circuito.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "69a7cc63-173b-467c-87c5-f0924b943f34",
      "metadata": {},
      "outputs": [],
      "source": [
        "options = SamplerOptions()\n",
        "options.default_shots = 10000\n",
        "options.dynamical_decoupling.enable = False\n",
        "options.twirling.enable_gates = False\n",
        "options.twirling.enable_measure = False"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e9311a78-cdc7-4ce2-9716-a0cb5fc03589",
      "metadata": {},
      "source": [
        "Agora, enviaremos os trabalhos usando o modo em lote.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "6c1ba1d4-b4ed-4781-99f5-41e3f93672d7",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID cwxf7wq60bqg008pvt8g\n"
          ]
        }
      ],
      "source": [
        "with Batch(backend=backend) as batch:\n",
        "    sampler = SamplerV2(options=options)\n",
        "    cut_job = sampler.run(subexperiments)\n",
        "\n",
        "print(f\"Job ID {cut_job.job_id()}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "id": "54ca98b9-7f31-45d2-910a-97ad29b37a0d",
      "metadata": {},
      "outputs": [],
      "source": [
        "result = cut_job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dd7cbb19-22ab-4e5a-bd18-3c7b06f67478",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-result-in-desired-classical-format\" />\n",
        "\n",
        "## Etapa 4: Pós-processamento e retorno do resultado no formato clássico desejado\n",
        "\n",
        "<ul>\n",
        "  <li>Entrada: Distribuições de quase-probabilidade</li>\n",
        "  <li>Saída: Valores de expectativa reconstruídos</li>\n",
        "</ul>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "3ee4af4c-4585-4a8d-87a6-921c2cdb1bd2",
      "metadata": {},
      "outputs": [],
      "source": [
        "reconstructed_expvals = reconstruct_expectation_values(\n",
        "    result,\n",
        "    coefficients,\n",
        "    paulis,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f2d78c56-001c-4fd5-97eb-6d45b0f84bda",
      "metadata": {},
      "source": [
        "Agora calculamos a média dos observáveis do tipo Z de weight-1 e weight-2.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "00714269-8c72-47eb-8651-3e2f5f65d505",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Average of weight-1 expectation values is -0.741733944954063\n",
            "Average of weight-2 expectation values is 0.6968862385320495\n"
          ]
        }
      ],
      "source": [
        "cut_weight_1 = np.mean(reconstructed_expvals[:num_qubits])\n",
        "cut_weight_2 = np.mean(reconstructed_expvals[num_qubits:])\n",
        "\n",
        "print(f\"Average of weight-1 expectation values is {cut_weight_1}\")\n",
        "print(f\"Average of weight-2 expectation values is {cut_weight_2}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1d15b180-107a-4078-afad-d306cf3098f5",
      "metadata": {},
      "source": [
        "<span id=\"cross-verify-obtain-uncut-expectation-value\" />\n",
        "\n",
        "### Verificação cruzada: Obter valor esperado não cortado\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b6387268-cbd6-4766-a43d-154e461dfbc4",
      "metadata": {},
      "source": [
        "É útil verificar a vantagem da técnica de corte de circuito em relação à técnica sem corte. Aqui, calcularemos os valores de expectativa sem cortar o circuito. Observe que esse circuito sem cortes sofrerá com um grande número de portas SWAP necessárias para implementar a operação de 2 qubits entre o primeiro e o último qubits. Usaremos a função `sampled_expectation_value` para obter os valores de expectativa do circuito sem cortes depois de obter a distribuição de probabilidade por meio de `SamplerV2`. Isso permite um uso homogêneo do primitivo em todas as instâncias. No entanto, observe que também poderíamos ter usado o site `EstimatorV2` para calcular diretamente os valores de expectativa.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "id": "0fcd5c53-703d-4e67-93d5-3ee4a7870753",
      "metadata": {},
      "outputs": [],
      "source": [
        "if ansatz.num_clbits == 0:\n",
        "    ansatz.measure_all()\n",
        "\n",
        "pm_uncut = generate_preset_pass_manager(\n",
        "    optimization_level=1, backend=backend, initial_layout=init_layout\n",
        ")\n",
        "\n",
        "transpiled_circuit = pm_uncut.run(ansatz)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "00e5b011-bec5-4917-a0d3-91943cad5927",
      "metadata": {},
      "outputs": [],
      "source": [
        "sampler = SamplerV2(mode=backend, options=options)\n",
        "uncut_job = sampler.run([transpiled_circuit])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "ec68d688-7de4-4d95-8e52-23a1eea7d94e",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The job id for the uncut clifford circuit is cwxfads2ac5g008jhe7g\n"
          ]
        }
      ],
      "source": [
        "uncut_job_id = uncut_job.job_id()\n",
        "print(f\"The job id for the uncut clifford circuit is {uncut_job_id}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "id": "1e04489f-3dc9-4253-aa9a-719952f260e3",
      "metadata": {},
      "outputs": [],
      "source": [
        "uncut_result = uncut_job.result()[0]\n",
        "uncut_counts = uncut_result.data.meas.get_counts()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fb150558-6571-4475-aa81-08860c2782d6",
      "metadata": {},
      "source": [
        "Agora, calcularemos os valores de expectativa média de todos os observáveis do tipo weight-1 e weight-2 Z sem corte.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "20991ea2-49a8-4258-9dd1-c064655674f1",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Average of weight-1 expectation values is -0.32494128440366965\n",
            "Average of weight-2 expectation values is 0.32340917431192656\n"
          ]
        }
      ],
      "source": [
        "uncut_expvals = [\n",
        "    sampled_expectation_value(uncut_counts, obs) for obs in paulis\n",
        "]\n",
        "\n",
        "uncut_weight_1 = np.mean(uncut_expvals[:num_qubits])\n",
        "uncut_weight_2 = np.mean(uncut_expvals[num_qubits:])\n",
        "\n",
        "print(f\"Average of weight-1 expectation values is {uncut_weight_1}\")\n",
        "print(f\"Average of weight-2 expectation values is {uncut_weight_2}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ed843ab6-9614-45a8-864a-932d897c0d22",
      "metadata": {},
      "source": [
        "<span id=\"visualize\" />\n",
        "\n",
        "### Visualizar\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "94eccfea-feb6-4a1c-a8fd-b7491ddb3b7d",
      "metadata": {},
      "source": [
        "Vamos agora visualizar o aprimoramento obtido para os observáveis weight-1 e weight-2 ao usar o corte de porta para o circuito de cadeia periódica\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "2ba8913f-ba35-409c-bc4c-5f28e3698f20",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/periodic-boundary-conditions-with-circuit-cutting/extracted-outputs/2ba8913f-ba35-409c-bc4c-5f28e3698f20-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "mpl.rcParams.update(mpl.rcParamsDefault)\n",
        "\n",
        "fig = plt.subplots(figsize=(12, 8), dpi=200)\n",
        "width = 0.25\n",
        "labels = [\"Weight-1\", \"Weight-2\"]\n",
        "x = np.arange(len(labels))\n",
        "\n",
        "ideal = [-1, 1]\n",
        "cut = [cut_weight_1, cut_weight_2]\n",
        "uncut = [uncut_weight_1, uncut_weight_2]\n",
        "\n",
        "br1 = np.arange(len(ideal))\n",
        "br2 = [x + width for x in br1]\n",
        "br3 = [x + width for x in br2]\n",
        "\n",
        "plt.bar(\n",
        "    br1, ideal, width=width, edgecolor=\"k\", label=\"Ideal\", color=\"#4589ff\"\n",
        ")\n",
        "plt.bar(br2, cut, width=width, edgecolor=\"k\", label=\"Cut\", color=\"#a56eff\")\n",
        "plt.bar(\n",
        "    br3, uncut, width=width, edgecolor=\"k\", label=\"Uncut\", color=\"#009d9a\"\n",
        ")\n",
        "\n",
        "plt.axhline(y=0, color=\"k\", linestyle=\"-\")\n",
        "\n",
        "plt.xticks([r + width for r in range(len(ideal))], labels, fontsize=14)\n",
        "plt.yticks(fontsize=14)\n",
        "\n",
        "plt.legend(fontsize=14)\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "55de226b-1c87-48c8-b5e3-ba28e0640110",
      "metadata": {},
      "source": [
        "<span id=\"summary\" />\n",
        "\n",
        "### Resumo\n",
        "\n",
        "Em resumo, calculamos os valores médios de expectativa dos observáveis dos tipos weight-1 e weight-2 Z para uma cadeia 1D periódica de 109 qubits. Para isso, nós\n",
        "\n",
        "* criamos um mapa de acoplamento virtual adicionando uma conectividade de longo alcance entre o primeiro e o último qubits da cadeia 1D e transpilamos o circuito.\n",
        "  * a transpilação nesse estágio nos permitiu evitar a sobrecarga de transpilar cada subexperimento separadamente após o corte,\n",
        "  * o uso do mapa de acoplamento virtual nos permitiu evitar portas SWAP adicionais para a operação de 2 qubits entre o primeiro e o último qubits.\n",
        "* removeu a conectividade de longo alcance do circuito transpilado por meio de corte de porta.\n",
        "* converteu os circuitos cortados em um conjunto de portas de base aplicando passagens de transpilação apropriadas.\n",
        "* executou os circuitos de corte no dispositivo IBM Quantum usando uma primitiva `SamplerV2` .\n",
        "* obteve o valor esperado reconstruindo os resultados dos circuitos cortados.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a556c909-8cac-4500-ab52-9146b47194bf",
      "metadata": {},
      "source": [
        "<span id=\"inference\" />\n",
        "\n",
        "### Inferência\n",
        "\n",
        "Observamos nos resultados que a média dos observáveis do tipo weight-1 $\\langle Z \\rangle$ e weight-2 $\\langle ZZ \\rangle$ melhora significativamente com o corte das portas periódicas. Observe que este estudo não inclui nenhuma técnica de supressão ou atenuação de erros. A melhoria observada se deve exclusivamente ao uso adequado do corte de porta para esse problema. Os resultados poderiam ter sido aprimorados ainda mais com o uso de técnicas de mitigação e supressão.\n",
        "\n",
        "Este estudo mostra um exemplo do uso eficaz do corte de portas para melhorar o desempenho da computação.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6b013b53",
      "metadata": {},
      "source": [
        "<span id=\"tutorial-survey\" />\n",
        "\n",
        "## Pesquisa tutorial\n",
        "\n",
        "Responda a esta breve pesquisa para fornecer feedback sobre este tutorial. Suas percepções nos ajudarão a melhorar nossas ofertas de conteúdo e a experiência do usuário.\n",
        "\n",
        "[Link para a pesquisa](https://your.feedback.ibm.com/jfe/form/SV_3fQQYAIjTxvIChg)\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.5,
    "qpuSeconds": 120
  },
  "nbformat": 4,
  "nbformat_minor": 5
}