{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "frontmatter",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Iniciação rápida\"\n",
        "description: \"Guia de início rápido para a versão mais recente do Qiskit Paulice\"\n",
        "---\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "intro",
      "metadata": {},
      "source": [
        "<span id=\"quickstart\" />\n",
        "\n",
        "# Iniciação rápida\n",
        "\n",
        "`qiskit-paulice` Este guia apresenta um exemplo mínimo funcional do pacote. Utilizamos [verificações de Pauli no espaço-tempo](https://arxiv.org/abs/2504.15725) para detectar erros durante a execução de um circuito de Clifford e, em seguida, selecionamos posteriormente apenas as amostras nas quais não foi detectado nenhum erro. Para conhecer um fluxo de trabalho completo e mais detalhado que quantifica a melhoria na fidelidade, consulte o [tutorial aprofundado](https://github.com/Qiskit/qiskit-paulice/blob/main/docs/guides/low_overhead_error_detection_using_spacetime_codes.ipynb).\n",
        "\n",
        "**Etapas do fluxo de trabalho**\n",
        "\n",
        "1. Prepare os dados de entrada: um circuito de carga útil de Clifford, os qubits-alvo/ancilla que abrigarão as verificações e um modelo de ruído.\n",
        "2. Encontre boas verificações de Pauli no espaço-tempo e adicione-as ao circuito.\n",
        "3. Faça um teste no circuito verificado.\n",
        "4. Selecione apenas as amostras nas quais não foi detectado nenhum erro.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "build-circuit",
      "metadata": {},
      "source": [
        "<span id=\"1-prepare-the-inputs\" />\n",
        "\n",
        "## 1. Prepare os dados de entrada\n",
        "\n",
        "`add_pauli_checks` recebe um **circuito** de Clifford com pelo menos uma medição terminal, os **qubits-alvo** que serão usados para implementar as verificações e um **modelo de ruído** utilizado para avaliar as verificações candidatas. `ibm_boston`Aqui, construímos um circuito de Clifford aleatório de profundidade rasa, o dispomos em uma cadeia de qubits físicos do tipo “ 1D ”, emparelhamos cada qubit de carga útil com um qubit auxiliar vizinho (de modo que uma verificação não precise de portas SWAP) e inferimos um modelo aproximado de ruído despolarizante a partir de dados de benchmark do backend.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "make-circuit",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/qiskit-addon-paulice/guides/quickstart/extracted-outputs/make-circuit-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import numpy as np\n",
        "from qiskit import QuantumCircuit\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_paulice.layout import get_check_qubits\n",
        "from qiskit_paulice.noise_models import NoiseModel\n",
        "\n",
        "# Backend and a 1D chain of physical qubits to run on\n",
        "backend = QiskitRuntimeService().backend(\"ibm_boston\")\n",
        "layout = [68, 69, 78, 89, 90, 91, 98, 111, 112, 113, 119, 133]\n",
        "\n",
        "# A shallow brickwork random Clifford payload circuit\n",
        "rng = np.random.default_rng(1764)\n",
        "circuit = QuantumCircuit(len(layout))\n",
        "circuit.h(range(circuit.num_qubits))\n",
        "for d in range(4):\n",
        "    for i in range(d % 2, circuit.num_qubits - 1, 2):\n",
        "        circuit.cz(i, i + 1)\n",
        "    for q in range(circuit.num_qubits):\n",
        "        if rng.integers(0, 2):\n",
        "            circuit.sx(q)\n",
        "        if rng.integers(0, 2):\n",
        "            circuit.s(q)\n",
        "circuit.measure_all()\n",
        "\n",
        "# Pair each payload qubit with a neighboring ancilla to host a check (no SWAPs needed)\n",
        "target_qubits, ancilla_qubits = get_check_qubits(backend.coupling_map, layout)\n",
        "\n",
        "# A rough depolarizing noise model from backend benchmark data, used to score checks\n",
        "noise_model = NoiseModel.from_backend(\n",
        "    backend, layout, uniform_gate_noise=True\n",
        ")\n",
        "\n",
        "circuit.draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "add-checks-md",
      "metadata": {},
      "source": [
        "<span id=\"2-find-and-add-spacetime-pauli-checks\" />\n",
        "\n",
        "## 2. Encontrar e adicionar verificações de Pauli no espaço-tempo\n",
        "\n",
        "`add_pauli_checks` procura por verificações eficazes e de baixo peso para cada qubit-alvo e as adiciona ao circuito, retornando uma sequência de `CheckedCircuit` instâncias. As `CheckedCircuit` instâncias contêm um número crescente de verificações, desde `0` verificações até uma verificação por qubit-alvo. Cada verificação melhora a capacidade de detecção de erros, em troca de um aumento ligeiro na profundidade do circuito. Para este exemplo, utilizaremos o circuito com uma verificação em cada qubit-alvo.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "add-checks",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/qiskit-addon-paulice/guides/quickstart/extracted-outputs/add-checks-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit_paulice import add_pauli_checks\n",
        "\n",
        "# The circuit has virtual qubits, so we specify our target qubits with virtual indices\n",
        "target_qubits_v = [layout.index(q) for q in target_qubits]\n",
        "\n",
        "# Add spacetime Pauli checks\n",
        "checked_circuit = add_pauli_checks(circuit, target_qubits_v, noise_model)[-1]\n",
        "checked_circuit.circuit.draw(\"mpl\", fold=-1, scale=0.4, idle_wires=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "postselect-md",
      "metadata": {},
      "source": [
        "<span id=\"3-sample-the-checked-circuit\" />\n",
        "\n",
        "## 3. Testar o circuito verificado\n",
        "\n",
        "`ibm_boston`Antes de realizar a amostragem, transpilamos o circuito verificado para qubits físicos (`initial_layout = layout + ancilla_qubits`) e para o conjunto de portas da base nativa do. Para simular uma QPU com ruído, realizamos amostragens com um backend do estabilizador Aer com ruído, cujas taxas de erro correspondem às `noise_model` utilizadas para selecionar os checks.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "sample",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "sampled 1000 shots\n"
          ]
        }
      ],
      "source": [
        "from qiskit import transpile\n",
        "from qiskit_aer import AerSimulator\n",
        "from qiskit_aer.noise import NoiseModel as AerNoiseModel\n",
        "from qiskit_aer.noise import ReadoutError, depolarizing_error\n",
        "\n",
        "# Transpile once: lay the checked circuit out on our qubits and into the native basis\n",
        "isa_circuit = transpile(\n",
        "    checked_circuit.circuit,\n",
        "    backend,\n",
        "    initial_layout=layout + ancilla_qubits,\n",
        "    optimization_level=0,\n",
        ")\n",
        "\n",
        "# Build an Aer noise model matching the depolarizing model used to pick checks\n",
        "aer_noise = AerNoiseModel()\n",
        "aer_noise.add_all_qubit_quantum_error(\n",
        "    depolarizing_error(noise_model.gate_noise, 2), [\"cz\"]\n",
        ")\n",
        "p = noise_model.readout_noise\n",
        "aer_noise.add_all_qubit_readout_error(ReadoutError([[1 - p, p], [p, 1 - p]]))\n",
        "simulator = AerSimulator(method=\"stabilizer\", noise_model=aer_noise)\n",
        "\n",
        "counts = (\n",
        "    simulator.run(isa_circuit, shots=1000, seed_simulator=1764)\n",
        "    .result()\n",
        "    .get_counts()\n",
        ")\n",
        "print(f\"sampled {sum(counts.values())} shots\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "postselect-step-md",
      "metadata": {},
      "source": [
        "<span id=\"4-postselect-samples-with-no-detected-error\" />\n",
        "\n",
        "## 4. Amostras selecionadas após a análise, sem erros detectados\n",
        "\n",
        "`get_postselection_method` associa cada tentativa ao seu vetor de síndrome; mantemos apenas as tentativas com síndrome composta inteiramente por zeros — aquelas nas quais nenhuma verificação detectou um erro. A descarte das imagens sinalizadas remove os erros detectados da distribuição restante, melhorando sua fidelidade em troca de uma taxa de amostragem menor. Consulte o [tutorial](https://github.com/Qiskit/qiskit-paulice/blob/main/docs/guides/low_overhead_error_detection_using_spacetime_codes.ipynb) para uma comparação quantitativa da fidelidade.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "postselect",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "kept 927 of 1000 shots (93%)\n"
          ]
        }
      ],
      "source": [
        "# Keep only the shots in which no check reported an error\n",
        "ps_fn = checked_circuit.get_postselection_method()\n",
        "counts_postselected = {\n",
        "    bs: n for bs, n in counts.items() if not ps_fn(bs).any()\n",
        "}\n",
        "\n",
        "kept, total = sum(counts_postselected.values()), sum(counts.values())\n",
        "print(f\"kept {kept} of {total} shots ({kept / total:.0%})\")"
      ]
    },
    {
      "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"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}