{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "frontmatter",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"빠른 시작\"\n",
        "description: \"최신 버전의 Qiskit Paulice 빠른 시작 가이드\"\n",
        "---\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "intro",
      "metadata": {},
      "source": [
        "<span id=\"quickstart\" />\n",
        "\n",
        "# 빠른 시작\n",
        "\n",
        "이 가이드에서는 해당 `qiskit-paulice` 패키지의 최소 실행 가능한 예제를 보여줍니다. 우리는 클리포드 회로 실행 중 오류를 탐지하기 위해 [시공간 파울리 검증을](https://arxiv.org/abs/2504.15725) 사용한 다음, 오류가 탐지되지 않은 샘플만을 사후 선별합니다. 정확도 향상을 수치화한, 보다 상세한 종단간 워크플로를 확인하려면 [심층](https://github.com/Qiskit/qiskit-paulice/blob/main/docs/guides/low_overhead_error_detection_using_spacetime_codes.ipynb) 튜토리얼을 참조하십시오.\n",
        "\n",
        "**워크플로우 단계**\n",
        "\n",
        "1. 입력 데이터를 준비합니다: 클리포드 페이로드 회로, 체크 연산을 수행할 대상/보조 큐비트, 그리고 잡음 모델.\n",
        "2. 적절한 시공간 파울리 검사 조건을 찾아 회로에 추가하십시오.\n",
        "3. 체크된 회로의 신호를 측정해 보십시오.\n",
        "4. 오류가 감지되지 않은 샘플만 선별하여 게시하십시오.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "build-circuit",
      "metadata": {},
      "source": [
        "<span id=\"1-prepare-the-inputs\" />\n",
        "\n",
        "## 1. 입력 데이터 준비하기\n",
        "\n",
        "`add_pauli_checks` 최소 하나의 단말 측정이 포함된 클리포드 **회로**, 검증을 구현하는 데 사용될 **대상 큐비트**, 그리고 후보 검증에 대한 점수를 매기는 데 사용되는 **노이즈 모델을** 입력으로 받습니다. `ibm_boston`여기서는 얕은 랜덤 클리포드 회로를 구축하고, 이를 물리적 큐비트로 구성된 1D 체인에 배치하며, 각 페이로드 큐비트를 인접한 보조 큐비트와 짝지은 뒤(따라서 검사 시 SWAP 게이트가 필요하지 않음), 백엔드 벤치마크 데이터를 바탕으로 대략적인 탈분극 잡음 모델을 도출합니다.\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. 시공간 파울리 검사 조건 찾기 및 추가하기\n",
        "\n",
        "`add_pauli_checks` 각 대상 큐비트에 대해 효과적이고 경량인 검사 방법을 찾아 회로에 추가한 뒤, 일련의 `CheckedCircuit` 인스턴스 시퀀스를 반환합니다. 이 `CheckedCircuit` 사례들에는 대상 큐비트당 1회 검사까지, `0` 검사 횟수가 점차 증가하는 경우가 포함되어 있습니다. 각 검사는 회로 깊이가 약간 증가하는 대가로 오류 탐지 능력을 향상시킵니다. 이 예제에서는 모든 대상 큐비트에 대한 검사가 포함된 회로를 사용할 것입니다.\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. 점검한 회로의 신호를 샘플링한다\n",
        "\n",
        "`ibm_boston`샘플링을 수행하기 전에, 검증된 회로를 물리적 큐비트(`initial_layout = layout + ancilla_qubits`)로 변환하고 의 기본 기저 게이트 집합으로 변환합니다. 잡음이 있는 QPU를 모방하기 위해, 체크를 선택하는 데 `noise_model` 사용된 오류율과 일치하는 잡음이 있는 Aer 안정화 백엔드를 사용하여 샘플링합니다.\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. 오류가 감지되지 않은 사후 선별 샘플\n",
        "\n",
        "`get_postselection_method` 각 샷을 해당 신드롬 벡터에 매핑하며, 신드롬 값이 모두 0인 샷, 즉 오류 검출에서 오류가 발견되지 않은 샷만 유지합니다. 표시된 샷을 제외하면, 남아 있는 분포에서 감지된 오류가 제거되어 샘플링 빈도는 낮아지지만 정확도는 향상됩니다. 정량적인 충실도 비교에 대해서는 [튜토리얼](https://github.com/Qiskit/qiskit-paulice/blob/main/docs/guides/low_overhead_error_detection_using_spacetime_codes.ipynb) 을 참고하세요.\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
}