{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "492d7cec",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"CHSH 부등식\"\n",
        "description: \"추정기(Estimator) 프리미티브를 사용하여 양자 컴퓨터에서 CHSH 부등식의 위반을 입증하는 실험을 실행하십시오.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore zorder Tsirelson */}\n",
        "\n",
        "<span id=\"chsh-inequality\" />\n",
        "\n",
        "# CHSH 부등식\n",
        "\n",
        "*예상 소요 시간: Heron r3 프로세서에서 2분 (참고: 이는 단지 추정치일 뿐입니다.) (실행 시간은 다를 수 있습니다.)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a57d9139",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## 학습 성과\n",
        "\n",
        "* 매개변수화된 벨 상태 CHSH 회로를 구성하고, CHSH 증인을 구성하는 네 가지 기대값을 측정하는 방법.\n",
        "* 프라이머리 함수를 [`EstimatorV2`](/docs/api/qiskit-ibm-runtime/estimator-v2) 한 번 호출하여 매개변수 스윕 시 여러 관측량의 기대값을 계산하는 방법.\n",
        "* 하드웨어에 제출하기 전에 잡음이 있는 로컬 시뮬레이터에서 양자 워크플로우를 검증하는 방법. `AerSimulator.from_backend`\n",
        "* IBM Quantum® 하드웨어에서 다수의 독립적인 벨 쌍을 병렬로 실행하여 CHSH 실험을 장치 전체에 걸친 얽힘 벤치마크로 확장하는 방법.\n",
        "\n",
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## 전제조건\n",
        "\n",
        "* [실전 얽힘](/learning/courses/basics-of-quantum-information/entanglement-in-action/chsh-game) : 벨 상태와 CHSH 게임에 관한 강의.\n",
        "* [`SparsePauliOp`](/docs/api/qiskit/qiskit.quantum_info.SparsePauliOp) 그리고 ‘ Qiskit primitives[ ’ 소개](/docs/guides/primitives).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f956eda1",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## 배경\n",
        "\n",
        "이 튜토리얼에서는 양자 컴퓨터에서 실험을 실행하여 추정기 프리미티브가 CHSH 부등식을 위반하는 것을 증명합니다.\n",
        "\n",
        "클라우저(Clauser), 호른(Horne), 시모니(Shimony), 홀트(Holt)의 이름을 딴 CHSH 부등식은 벨의 정리(1969)를 실험적으로 검증하는 데 사용된다. 이 정리는 국소적 숨은 변수 이론으로는 양자역학에서 얽힘이 초래하는 일부 결과를 설명할 수 없다고 주장한다. CHSH 부등식의 위반을 입증하는 것은 양자역학이 국소적 숨은 변수 이론과 양립할 수 없음을 보여주는 것으로, 이는 양자역학을 이해하는 데 있어 기초가 되는 실험이다.\n",
        "\n",
        "2022년 노벨 물리학상은 알랭 아스펙트, 존 클라우저, 안톤 자이링거에게 수여되었는데, 이는 부분적으로 양자 정보 과학 분야의 선구적인 업적, 특히 얽힌 광자를 이용한 실험을 통해 벨 부등식의 위반을 입증한 공로를 인정받은 결과이다.\n",
        "\n",
        "이번 실험에서는 얽힘 쌍을 생성한 뒤, 각 큐비트를 서로 다른 두 가지 기저에서 측정할 것입니다. 첫 번째 큐비트의 기저를 $A$ 와 $a$ 로, 두 번째 큐비트의 기저를 $B$ 와 $b$ 로 표기하겠습니다. 이를 통해 CHSH 양 $S_1$ 을 계산할 수 있습니다:\n",
        "\n",
        "$$\n",
        "S_1 = A(B-b) + a(B+b).\n",
        "$$\n",
        "\n",
        "각 관측값은 $+1$ 또는 $-1$ 중 하나입니다. 분명히, $B\\pm b$ 중 한 항은 $0$ 이어야 하고, 다른 한 항은 $\\pm 2$ 이어야 합니다. 따라서, $S_1 = \\pm 2$ 입니다. $S_1$ 의 평균값은 다음 부등식을 만족해야 합니다:\n",
        "\n",
        "$$\n",
        "|\\langle S_1 \\rangle|\\leq 2.\n",
        "$$\n",
        "\n",
        "$S_1$ 를 $A$, $a$, $B$, $b$ 에 대해 전개하면 다음과 같습니다:\n",
        "\n",
        "$$\n",
        "|\\langle S_1 \\rangle| = |\\langle AB \\rangle - \\langle Ab \\rangle + \\langle aB \\rangle + \\langle ab \\rangle| \\leq 2.\n",
        "$$\n",
        "\n",
        "다른 CHSH 수량을 정의할 수 있습니다 $S_2$ :\n",
        "\n",
        "$$\n",
        "S_2 = A(B+b) - a(B-b),\n",
        "$$\n",
        "\n",
        "이로 인해 또 다른 부등식이 도출되는데:\n",
        "\n",
        "$$\n",
        "|\\langle S_2 \\rangle| = |\\langle AB \\rangle + \\langle Ab \\rangle - \\langle aB \\rangle + \\langle ab \\rangle| \\leq 2.\n",
        "$$\n",
        "\n",
        "만약 양자역학이 국소적 숨은 변수 이론으로 설명될 수 있다면, 이러한 부등식은 항상 성립할 것이다. 이 튜토리얼에서 보여준 바와 같이, 양자 컴퓨터에서는 이러한 원리가 위반될 수 있으므로, 양자역학은 국소 숨겨진 변수 이론과 양립할 수 없다.\n",
        "\n",
        "우리는 벨 상태 $|\\Phi^+\\rangle = \\frac{|00\\rangle + |11\\rangle}{\\sqrt{2}}$ 를 준비하여 얽힌 쌍을 생성합니다. ‘Estimator’ 기본 기능을 사용하여, 원시 계수값으로부터 재구성할 필요 없이 기대값 $\\langle AB \\rangle, \\langle Ab \\rangle, \\langle aB \\rangle$ 및 $\\langle ab \\rangle$ 를 직접 구합니다. 우리는 $Z$ 와 $X$ 기저에서 두 번째 큐비트를 측정합니다. 첫 번째 큐비트 역시 직교 기저에서 측정되지만, 회전 각도 $\\theta$ 를 $0$ 와 $2\\pi$ 사이에서 스윕합니다. Estimator 프리미티브는 이 매개변수 스윕을 단일 [프리미티브 통합 블록( PUB )](/docs/guides/primitive-input-output) 에서 평가합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c7346a67",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## 요구사항\n",
        "\n",
        "이 튜토리얼을 시작하기 전에 다음 항목이 설치되어 있는지 확인하십시오:\n",
        "\n",
        "* Qiskit SDK v2.0 또는 그 이후 버전, [시각화](/docs/api/qiskit/visualization) 기능 지원\n",
        "* Qiskit Runtime v0.40 또는 그 이후 (`pip install qiskit-ibm-runtime`)\n",
        "* Qiskit Aer v0.17 이상 (`pip install qiskit-aer`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d5ffeb42",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## 설정\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "323b27db",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-05-19T22:38:49.177326Z",
          "iopub.status.busy": "2026-05-19T22:38:49.177203Z",
          "iopub.status.idle": "2026-05-19T22:38:49.804694Z",
          "shell.execute_reply": "2026-05-19T22:38:49.804154Z"
        }
      },
      "outputs": [],
      "source": [
        "# General\n",
        "import numpy as np\n",
        "\n",
        "# Qiskit imports\n",
        "from qiskit import QuantumCircuit\n",
        "from qiskit.circuit import Parameter\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "# `qiskit-ibm-runtime` imports\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime import EstimatorV2 as Estimator\n",
        "\n",
        "# Qiskit Aer for local noisy simulation\n",
        "from qiskit_aer import AerSimulator\n",
        "\n",
        "# Plotting routines\n",
        "import matplotlib.pyplot as plt\n",
        "import matplotlib.ticker as tck"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "fd284a0f",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-05-19T22:38:49.806301Z",
          "iopub.status.busy": "2026-05-19T22:38:49.806113Z",
          "iopub.status.idle": "2026-05-19T22:38:53.208796Z",
          "shell.execute_reply": "2026-05-19T22:38:53.208025Z"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'ibm_pittsburgh'"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Select an IBM Quantum backend.\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    min_num_qubits=127, operational=True, simulator=False\n",
        ")\n",
        "backend.name"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ca035271",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-simulator-example\" />\n",
        "\n",
        "## 소규모 시뮬레이터 예시\n",
        "\n",
        "하드웨어 작업을 제출하기 전에, 로컬의 노이즈가 포함된 시뮬레이터에서 전체 워크플로를 검증합니다. 우리는 를 `AerSimulator.from_backend(backend)` 사용하여 사용자가 선택한 백엔드의 노이즈 모델과 커플링 맵을 상속하는 시뮬레이터를 구축하므로, 시뮬레이터의 응답은 하드웨어에서 예상되는 결과와 질적으로 유사합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0539a796",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### 1단계: 고전적 입력을 양자 문제에 매핑하기\n",
        "\n",
        "CHSH 회로는 단일 매개변수 $\\theta$ 로 표현되며, 이 매개변수는 첫 번째 큐비트의 측정 기저를 훑어 나갑니다. 이 [`Estimator`](/docs/api/qiskit-ibm-runtime/estimator-v2) 프리미티브는 분석을 단순화합니다. 관측 가능한 변수의 기대값을 직접 반환하며, 단 한 번의 호출로 다양한 매개변수 값에 대해 매개변수화된 회로를 평가할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "c3f57d25",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-05-19T22:38:53.210931Z",
          "iopub.status.busy": "2026-05-19T22:38:53.210786Z",
          "iopub.status.idle": "2026-05-19T22:38:53.349189Z",
          "shell.execute_reply": "2026-05-19T22:38:53.348782Z"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/chsh-inequality/extracted-outputs/c3f57d25-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "theta = Parameter(r\"$\\theta$\")\n",
        "\n",
        "chsh_circuit = QuantumCircuit(2)\n",
        "chsh_circuit.h(0)\n",
        "chsh_circuit.cx(0, 1)\n",
        "chsh_circuit.ry(theta, 0)\n",
        "chsh_circuit.draw(output=\"mpl\", idle_wires=False, style=\"iqp\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "af999dde",
      "metadata": {},
      "source": [
        "다음으로, 매개변수화된 회로( $0$, $0.1\\pi$, $0.2\\pi$,..., $1.9\\pi$, $2\\pi$ )를 평가할 $0$ 부터 $2\\pi$ 까지의 21개 위상 값 목록을 생성합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "9d587e2f",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-05-19T22:38:53.350400Z",
          "iopub.status.busy": "2026-05-19T22:38:53.350337Z",
          "iopub.status.idle": "2026-05-19T22:38:53.352045Z",
          "shell.execute_reply": "2026-05-19T22:38:53.351729Z"
        }
      },
      "outputs": [],
      "source": [
        "number_of_phases = 21\n",
        "phases = np.linspace(0, 2 * np.pi, number_of_phases)\n",
        "# Phases need to be expressed as a list of lists for the Estimator PUB\n",
        "individual_phases = [[ph] for ph in phases]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "af917afb",
      "metadata": {},
      "source": [
        "마지막으로 관측량을 정의합니다. 첫 번째 큐비트는 $\\theta$ 로 회전된 축을 따라 측정되며, 두 번째 큐비트는 $Z$ 및 $X$ 에서 측정됩니다. 이러한 선택을 바탕으로, 네 개의 CHSH 상관함수는 파울리 연산자 $ZZ$, $ZX$, $XZ$ 및 $XX$ 에 대응됩니다:\n",
        "\n",
        "$$\n",
        "\\langle S_1 \\rangle = \\langle ZZ \\rangle - \\langle ZX \\rangle + \\langle XZ \\rangle + \\langle XX \\rangle,\n",
        "$$\n",
        "\n",
        "$$\n",
        "\\langle S_2 \\rangle = \\langle ZZ \\rangle + \\langle ZX \\rangle - \\langle XZ \\rangle + \\langle XX \\rangle.\n",
        "$$\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "21ae6238",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-05-19T22:38:53.353007Z",
          "iopub.status.busy": "2026-05-19T22:38:53.352948Z",
          "iopub.status.idle": "2026-05-19T22:38:53.355217Z",
          "shell.execute_reply": "2026-05-19T22:38:53.354857Z"
        }
      },
      "outputs": [],
      "source": [
        "# <S_1> = <ZZ> - <ZX> + <XZ> + <XX>\n",
        "observable1 = SparsePauliOp.from_list(\n",
        "    [(\"ZZ\", 1), (\"ZX\", -1), (\"XZ\", 1), (\"XX\", 1)]\n",
        ")\n",
        "\n",
        "# <S_2> = <ZZ> + <ZX> - <XZ> + <XX>\n",
        "observable2 = SparsePauliOp.from_list(\n",
        "    [(\"ZZ\", 1), (\"ZX\", 1), (\"XZ\", -1), (\"XX\", 1)]\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2d571aa2",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### 2단계: 양자 하드웨어 실행을 위한 문제 최적화\n",
        "\n",
        "V2 프리미티브는 대상 시스템이 지원하는 명령어 및 연결 방식(명령어 집합 아키텍처, 즉 ISA, 회로 및 관측 가능 변수)에 부합하는 회로와 관측 가능 변수만 허용합니다. 우리는 백엔드에서 를 `AerSimulator` 빌드하고 시뮬레이터의 대상 환경에 맞춰 트랜스파일링하여, 동일한 패스 매니저가 엔드투엔드 방식으로 실행되도록 합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "3e139a89",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-05-19T22:38:53.356197Z",
          "iopub.status.busy": "2026-05-19T22:38:53.356140Z",
          "iopub.status.idle": "2026-05-19T22:38:56.713188Z",
          "shell.execute_reply": "2026-05-19T22:38:56.712683Z"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/chsh-inequality/extracted-outputs/3e139a89-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Build a noisy simulator from the ibm_pittsburgh backend\n",
        "aer_sim = AerSimulator.from_backend(backend)\n",
        "\n",
        "pm = generate_preset_pass_manager(target=aer_sim.target, optimization_level=3)\n",
        "chsh_isa_circuit = pm.run(chsh_circuit)\n",
        "chsh_isa_circuit.draw(output=\"mpl\", idle_wires=False, style=\"iqp\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2817b069",
      "metadata": {},
      "source": [
        "`SparsePauliOp.apply_layout`또한,.를 사용하여 관측 가능한 양을 트랜스파일된 회로의 큐비트 배열에 맞게 변환합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "d1faa7ab",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-05-19T22:38:56.714405Z",
          "iopub.status.busy": "2026-05-19T22:38:56.714288Z",
          "iopub.status.idle": "2026-05-19T22:38:56.716319Z",
          "shell.execute_reply": "2026-05-19T22:38:56.715992Z"
        }
      },
      "outputs": [],
      "source": [
        "isa_observable1 = observable1.apply_layout(layout=chsh_isa_circuit.layout)\n",
        "isa_observable2 = observable2.apply_layout(layout=chsh_isa_circuit.layout)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e734572e",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### 3단계: `Qiskit primitives` 명령어로 실행합니다\n",
        "\n",
        "모드에서 `aer_sim``EstimatorV2` 매개변수 스윕을 실행합니다. Estimator `run()` 메서드는 PUB의 반복 가능한 객체를 매개변수로 받습니다. `(circuit, observables, parameter_values, precision)`각 PUB 파일은 다음과 같은 형식을 갖습니다. 두 관측 변수를 함께 전달하여 동일한 매개변수 스윕을 공유하도록 합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "7f954aeb",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-05-19T22:38:56.717549Z",
          "iopub.status.busy": "2026-05-19T22:38:56.717473Z",
          "iopub.status.idle": "2026-05-19T22:38:58.217539Z",
          "shell.execute_reply": "2026-05-19T22:38:58.217000Z"
        }
      },
      "outputs": [],
      "source": [
        "# Use the AerSimulator-backed Estimator to validate the workflow locally\n",
        "estimator_sim = Estimator(mode=aer_sim)\n",
        "\n",
        "pub = (\n",
        "    chsh_isa_circuit,  # ISA circuit\n",
        "    [[isa_observable1], [isa_observable2]],  # ISA observables\n",
        "    individual_phases,  # Parameter values\n",
        ")\n",
        "\n",
        "sim_result = estimator_sim.run(pubs=[pub]).result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9c5230fc",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-result-in-desired-classical-format\" />\n",
        "\n",
        "### 4단계: 후처리 수행 및 원하는 클래식 형식으로 결과 반환\n",
        "\n",
        "Estimator는 두 관측 가능 변수에 대한 기대값을 반환합니다. 이 값들을 $\\theta$ 에 그래프로 표시하고, 여기에 고전적 상한( $\\pm 2$ )과 치렐슨 상한( $\\pm 2\\sqrt{2}$ )을 함께 표시했습니다. 회색 음영 처리된 영역은 이 두 상한 사이의 차이를 나타냅니다. 이 대역 안에 있는 점들은 CHSH 부등식을 위반한다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "c8fd5140",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-05-19T22:38:58.219407Z",
          "iopub.status.busy": "2026-05-19T22:38:58.219306Z",
          "iopub.status.idle": "2026-05-19T22:38:58.285202Z",
          "shell.execute_reply": "2026-05-19T22:38:58.284609Z"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/chsh-inequality/extracted-outputs/c8fd5140-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "chsh1_sim = sim_result[0].data.evs[0]\n",
        "chsh2_sim = sim_result[0].data.evs[1]\n",
        "\n",
        "\n",
        "def plot_chsh(phases, chsh1, chsh2, title):\n",
        "    fig, ax = plt.subplots(figsize=(10, 6))\n",
        "\n",
        "    ax.plot(\n",
        "        phases / np.pi, chsh1, \"o-\", label=r\"$\\langle S_1 \\rangle$\", zorder=3\n",
        "    )\n",
        "    ax.plot(\n",
        "        phases / np.pi, chsh2, \"o-\", label=r\"$\\langle S_2 \\rangle$\", zorder=3\n",
        "    )\n",
        "\n",
        "    # classical bound +-2\n",
        "    ax.axhline(y=2, color=\"0.9\", linestyle=\"--\")\n",
        "    ax.axhline(y=-2, color=\"0.9\", linestyle=\"--\")\n",
        "\n",
        "    # quantum bound, +-2*sqrt(2)\n",
        "    ax.axhline(y=np.sqrt(2) * 2, color=\"0.9\", linestyle=\"-.\")\n",
        "    ax.axhline(y=-np.sqrt(2) * 2, color=\"0.9\", linestyle=\"-.\")\n",
        "    ax.fill_between(phases / np.pi, 2, 2 * np.sqrt(2), color=\"0.6\", alpha=0.7)\n",
        "    ax.fill_between(\n",
        "        phases / np.pi, -2, -2 * np.sqrt(2), color=\"0.6\", alpha=0.7\n",
        "    )\n",
        "\n",
        "    ax.xaxis.set_major_formatter(tck.FormatStrFormatter(\"%g $\\\\pi$\"))\n",
        "    ax.xaxis.set_major_locator(tck.MultipleLocator(base=0.5))\n",
        "\n",
        "    ax.set_xlabel(r\"$\\theta$\")\n",
        "    ax.set_ylabel(\"CHSH witness\")\n",
        "    ax.set_title(title)\n",
        "    ax.legend()\n",
        "    plt.show()\n",
        "\n",
        "\n",
        "plot_chsh(\n",
        "    phases,\n",
        "    chsh1_sim,\n",
        "    chsh2_sim,\n",
        "    \"CHSH witnesses from AerSimulator (ibm_pittsburgh noise model)\",\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e9744b84",
      "metadata": {},
      "source": [
        "이 시뮬레이터의 CHSH 증인은, 백엔드의 잡음 모델을 적용한 상태에서도 $\\theta$ 의 여러 값에서 이미 고전적 한계인 $\\pm 2$ 를 초과하고 있다. 시뮬레이션된 소자 잡음으로 인해 피크 값은 Tsirelson 상한 $\\pm 2\\sqrt{2}$ 에 약간 미치지 못합니다. 워크플로우 검증이 완료되었으므로, 이제 실제 하드웨어 단계로 넘어갑니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "747e948d",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## 대규모 하드웨어 예시\n",
        "\n",
        "CHSH 검정은 본질적으로 *2-큐비트* 실험이므로, 회로 하나를 더 크게 만든다고 해서 확장성이 향상되지는 않습니다. 대신, **여러 테스트를 병렬로** 실행함으로써 확장성을 확보합니다. 여기서는 연결성이 허용하는 한도 내에서 백엔드를 서로 겹치지 않는 벨 쌍으로 최대한 많이 타일링하고(결합 맵의 *매칭* ), 각 쌍에 대해 독립적인 CHSH 하위 회로를 실행하며, 이 모든 과정을 단일 작업 내에서 수행합니다.\n",
        "\n",
        "이를 통해 CHSH는 **장치** 전체를 아우르는 얽힘 품질 벤치마크로 기능하게 됩니다. 즉, 개별적으로 선별된 단일 쌍이 아닌, 칩의 상당 부분에 걸쳐 얽힘을 한 번에 테스트하며, 모든 쌍이 인접 쌍의 크로스톡 및 병렬 게이트 오류와 경쟁하는 현실적인 조건 하에서 수행됩니다. 모든 쌍에 대해 불평등 조건을 *동시에* 위반하는 것은 장치의 모든 곳에서 진정한 얽힘이 존재함을 입증한다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "3376bc73",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-05-19T22:38:58.286726Z",
          "iopub.status.busy": "2026-05-19T22:38:58.286656Z",
          "iopub.status.idle": "2026-05-19T22:38:59.198086Z",
          "shell.execute_reply": "2026-05-19T22:38:59.197690Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Tiling ibm_pittsburgh with 64 parallel Bell pairs (128 of 156 qubits)\n",
            "Job ID: d86efd5g7okc73el0rp0\n",
            "63/64 Bell pairs violated the CHSH inequality (mean peak witness 2.75, classical bound 2)\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/chsh-inequality/extracted-outputs/3376bc73-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# -------------------------Step 1: Map classical inputs to a quantum problem-------------------------\n",
        "# A CHSH test is bipartite, so we scale up by running one independent CHSH\n",
        "# experiment on every disjoint Bell pair the device can host. A greedy\n",
        "# matching of the coupling map gives a set of edges that share no qubits.\n",
        "num_qubits = backend.num_qubits\n",
        "used = set()\n",
        "pairs = []\n",
        "for qa, qb in backend.coupling_map.get_edges():\n",
        "    if qa not in used and qb not in used:\n",
        "        pairs.append((qa, qb))\n",
        "        used.update((qa, qb))\n",
        "num_pairs = len(pairs)\n",
        "print(\n",
        "    f\"Tiling {backend.name} with {num_pairs} parallel Bell pairs \"\n",
        "    f\"({2 * num_pairs} of {num_qubits} qubits)\"\n",
        ")\n",
        "\n",
        "# One parameterized CHSH sub-circuit per pair, all sharing the angle theta\n",
        "theta = Parameter(r\"$\\theta$\")\n",
        "chsh_circuit = QuantumCircuit(num_qubits)\n",
        "for qa, qb in pairs:\n",
        "    chsh_circuit.h(qa)\n",
        "    chsh_circuit.cx(qa, qb)\n",
        "    chsh_circuit.ry(theta, qa)\n",
        "\n",
        "# Embed the two CHSH observables onto each pair's qubits (identity elsewhere)\n",
        "obs1 = SparsePauliOp.from_list([(\"ZZ\", 1), (\"ZX\", -1), (\"XZ\", 1), (\"XX\", 1)])\n",
        "obs2 = SparsePauliOp.from_list([(\"ZZ\", 1), (\"ZX\", 1), (\"XZ\", -1), (\"XX\", 1)])\n",
        "observables = []\n",
        "for qa, qb in pairs:\n",
        "    observables.append([obs1.apply_layout([qa, qb], num_qubits)])\n",
        "    observables.append([obs2.apply_layout([qa, qb], num_qubits)])\n",
        "\n",
        "number_of_phases = 21\n",
        "phases = np.linspace(0, 2 * np.pi, number_of_phases)\n",
        "individual_phases = [[ph] for ph in phases]\n",
        "\n",
        "# -------------------------Step 2: Optimize problem for quantum hardware execution-------------------------\n",
        "pm = generate_preset_pass_manager(target=backend.target, optimization_level=3)\n",
        "chsh_isa_circuit = pm.run(chsh_circuit)\n",
        "isa_observables = [\n",
        "    [o[0].apply_layout(chsh_isa_circuit.layout)] for o in observables\n",
        "]\n",
        "\n",
        "# -------------------------Step 3: Execute using Qiskit primitives-------------------------\n",
        "estimator_hw = Estimator(mode=backend)\n",
        "estimator_hw.options.environment.job_tags = [\"TUT_CI\"]\n",
        "\n",
        "pub = (chsh_isa_circuit, isa_observables, individual_phases)\n",
        "job = estimator_hw.run(pubs=[pub])\n",
        "print(f\"Job ID: {job.job_id()}\")\n",
        "hw_result = job.result()\n",
        "\n",
        "# -------------------------Step 4: Post-process and return result in desired classical format-------------------------\n",
        "# evs has shape (2 * num_pairs, number_of_phases); rows alternate S1, S2\n",
        "evs = np.asarray(hw_result[0].data.evs)\n",
        "chsh1_all = evs[0::2]\n",
        "chsh2_all = evs[1::2]\n",
        "\n",
        "# A pair \"violates\" CHSH if its strongest witness exceeds the classical bound\n",
        "peak = np.maximum(\n",
        "    np.abs(chsh1_all).max(axis=1), np.abs(chsh2_all).max(axis=1)\n",
        ")\n",
        "n_violate = int(np.sum(peak > 2))\n",
        "print(\n",
        "    f\"{n_violate}/{num_pairs} Bell pairs violated the CHSH inequality \"\n",
        "    f\"(mean peak witness {peak.mean():.2f}, classical bound 2)\"\n",
        ")\n",
        "\n",
        "fig, ax = plt.subplots(figsize=(10, 6))\n",
        "\n",
        "# Faint individual per-pair curves\n",
        "for row in chsh1_all:\n",
        "    ax.plot(phases / np.pi, row, color=\"#1f77b4\", alpha=0.2, lw=1)\n",
        "for row in chsh2_all:\n",
        "    ax.plot(phases / np.pi, row, color=\"#ff7f0e\", alpha=0.2, lw=1)\n",
        "\n",
        "# Bold mean curves across all pairs\n",
        "ax.plot(\n",
        "    phases / np.pi,\n",
        "    chsh1_all.mean(axis=0),\n",
        "    color=\"#1f77b4\",\n",
        "    lw=2.5,\n",
        "    label=r\"$\\langle S_1 \\rangle$ (mean)\",\n",
        ")\n",
        "ax.plot(\n",
        "    phases / np.pi,\n",
        "    chsh2_all.mean(axis=0),\n",
        "    color=\"#ff7f0e\",\n",
        "    lw=2.5,\n",
        "    label=r\"$\\langle S_2 \\rangle$ (mean)\",\n",
        ")\n",
        "\n",
        "# classical bound +-2 and Tsirelson bound +-2*sqrt(2)\n",
        "ax.axhline(y=2, color=\"0.9\", linestyle=\"--\")\n",
        "ax.axhline(y=-2, color=\"0.9\", linestyle=\"--\")\n",
        "ax.axhline(y=np.sqrt(2) * 2, color=\"0.9\", linestyle=\"-.\")\n",
        "ax.axhline(y=-np.sqrt(2) * 2, color=\"0.9\", linestyle=\"-.\")\n",
        "ax.fill_between(phases / np.pi, 2, 2 * np.sqrt(2), color=\"0.6\", alpha=0.7)\n",
        "ax.fill_between(phases / np.pi, -2, -2 * np.sqrt(2), color=\"0.6\", alpha=0.7)\n",
        "\n",
        "ax.xaxis.set_major_formatter(tck.FormatStrFormatter(\"%g $\\\\pi$\"))\n",
        "ax.xaxis.set_major_locator(tck.MultipleLocator(base=0.5))\n",
        "ax.set_xlabel(r\"$\\theta$\")\n",
        "ax.set_ylabel(\"CHSH witness\")\n",
        "ax.set_title(\n",
        "    f\"CHSH witnesses for {num_pairs} parallel Bell pairs on {backend.name}\"\n",
        ")\n",
        "ax.legend()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3c32f01c",
      "metadata": {},
      "source": [
        "희미한 곡선들은 개별 벨 쌍을 나타내며, 굵은 곡선들은 장치 전체에 걸친 이들의 평균값을 나타냅니다. 모든 쌍은 양자역학이 예측한 것과 동일한 사인 곡선을 그리며, 희미한 곡선들 사이의 편차는 쌍마다 다른 잡음의 변동을 반영한다. 곡선이 회색 띠 영역에 들어가는 지점마다, 그 곡선은 $\\pm 2$ 의 고전적 경계를 넘어선 것이며, 인쇄된 요약본을 보면 사실상 모든 쌍이 동시에 CHSH 부등식을 위반한다는 사실이 확인된다.\n",
        "\n",
        "피크는 소자 잡음으로 인해 치렐슨 상한 $\\pm 2\\sqrt{2}$ 에는 미치지 못하지만, 결론은 분명하다. 즉, 백엔드는 단순히 미리 선정된 한 쌍의 입자뿐만 아니라 칩 전체에 걸쳐 동시에 진정한 얽힘 상태를 유지한다는 것이다. CHSH 실험이 “확장”되는 것은 바로 이러한 의미에서입니다. 즉, 하나의 더 큰 회로가 아니라, 모든 곳에서 동시에 얽힘을 검증하는 병렬 벤치마크로서 확장되는 것입니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "86e635a3",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 다음 단계\n",
        "\n",
        "<Admonition type=\"tip\" title=\"권장사항\">\n",
        "  이 글이 흥미로웠다면, 다음 자료도 참고해 보시기 바랍니다:\n",
        "\n",
        "  * [실전 얽힘](/learning/courses/basics-of-quantum-information/entanglement-in-action/chsh-game) : 존 왓루스가 진행하는 벨 상태와 CHSH 게임에 관한 강의.\n",
        "  * [Estimator 기본 요소 시작하기](/docs/guides/primitives) : PUB 및 매개변수 스윕에 대한 가이드.\n",
        "  * [큐비트 선별을 위한 실시간 벤치마킹](/docs/tutorials/real-time-benchmarking-for-qubit-selection) : 장치 전반에 걸쳐 큐비트 및 얽힘의 품질을 평가하는 또 다른 방법.\n",
        "  * [`SparsePauliOp` API 참조](/docs/api/qiskit/qiskit.quantum_info.SparsePauliOp).\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3"
    },
    "hours": 1,
    "qpuSeconds": 120
  },
  "nbformat": 4,
  "nbformat_minor": 5
}