{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "cdc8dc1e-0cff-46c1-94d0-97456d278e27",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"첫 번째 Qiskit Serverless 프로그램을 작성하세요\"\n",
        "description: \"병렬 트랜스파일레이션 프로그램을 생성하고 이를 IBM Quantum Platform 에 배포하여 재사용 가능한 원격 서비스로 활용하는 방법.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore mypath  */}\n",
        "\n",
        "<span id=\"write-your-first-qiskit-serverless-program\" />\n",
        "\n",
        "# 첫 번째 Qiskit Serverless 프로그램을 작성하세요\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b6d632cb-d884-4963-9c8d-8f3a3acd8a7d",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "<Accordion>\n",
        "  <AccordionItem title=\"패키지 버전\">\n",
        "    이 페이지의 코드는 다음 요구 사항을 사용하여 개발되었습니다.\n",
        "    다음 버전 이상을 사용하는 것이 좋습니다.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=1.3.1\n",
        "    qiskit-ibm-runtime~=0.34.0\n",
        "    qiskit-aer~=0.15.1\n",
        "    qiskit-serverless~=0.27.0\n",
        "    qiskit-ibm-catalog~=0.2\n",
        "    qiskit-addon-sqd~=0.8.1\n",
        "    qiskit-addon-utils~=0.1.0\n",
        "    qiskit-addon-mpf~=0.2.0\n",
        "    qiskit-addon-aqc-tensor~=0.1.2\n",
        "    qiskit-addon-obp~=0.1.0\n",
        "    scipy~=1.15.0\n",
        "    pyscf~=2.8.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1cc46aeb-aff6-4fab-9d78-69f2bfe98d98",
      "metadata": {},
      "source": [
        "<Admonition type=\"tip\">\n",
        "  **Qiskit Serverless 업그레이드를 진행 중이며, 기능이 빠르게 변화하고 있습니다.** 이 개발 단계 동안, 릴리스 노트와 최신 문서는 [Qiskit ServerlessGitHub](https://qiskit.github.io/qiskit-serverless/index.html) 페이지에서 확인하실 수 있습니다.\n",
        "</Admonition>\n",
        "\n",
        "이 예제는 도구를 `qiskit-serverless` 사용하여 병렬 트랜스파일링 프로그램을 만드는 방법을 보여주고, 이를 `qiskit-ibm-catalog` 구현하여 프로그램을 IBM Quantum Platform 에 업로드함으로써 재사용 가능한 원격 서비스로 활용하는 방법을 설명합니다.\n",
        "\n",
        "<span id=\"workflow-overview\" />\n",
        "\n",
        "## 작업 흐름 개요\n",
        "\n",
        "1. 로컬 디렉터리를 생성하고 프로그램 파일을 비워주세요 (`./source_files/transpile_remote.py`)\n",
        "2. 프로그램에 코드를 추가하여, Qiskit Serverless 에 업로드하면 회로를 트랜스파일링하도록 하세요\n",
        "3. Qiskit Serverless 에 인증하려면 `qiskit-ibm-catalog` 사용하십시오\n",
        "4. 프로그램을 Qiskit Serverless 에 업로드하세요\n",
        "\n",
        "프로그램을 업로드한 후, [‘첫 번째 Qiskit Serverless 워크로드를 원격으로](/docs/guides/serverless-run-first-workload) 실행하기’ 가이드를 따라 프로그램을 실행하여 회로를 트랜스파일할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cad16f43-8548-4849-a4b8-09059a8b747c",
      "metadata": {},
      "source": [
        "<span id=\"example-remote-transpilation-with-qiskit-serverless\" />\n",
        "\n",
        "## 예시: Qiskit Serverless 를 사용한 원격 트랜스파일링\n",
        "\n",
        "이 예제는 프로그램 파일을 생성하고 내용을 추가하는 과정을 단계별로 안내합니다. 이 파일을 `optimization_level`Qiskit Serverless 에 업로드하면, 지정된 `backend` 및 대상 을 기준으로 `circuit` 를 트랜스파일합니다.\n",
        "\n",
        "<Admonition type=\"tip\">\n",
        "  키스킷 서버리스를 사용하려면 워크로드의 `.py` 파일을 전용 디렉토리에 설정해야 합니다. 다음 구조는 모범 사례의 예입니다:\n",
        "\n",
        "  ```text\n",
        "  serverless_program\n",
        "  ├── program_uploader.ipynb\n",
        "  └── source_files\n",
        "      ├── transpile_remote.py\n",
        "      └── *.py\n",
        "  ```\n",
        "</Admonition>\n",
        "\n",
        "Serverless는 특정 디렉터리의 내용(이 예시에서는 디렉터리 `source_files` )을 업로드하여 원격으로 실행합니다. 이 설정들이 완료되면, 입력을 가져오고 출력을 `transpile_remote.py` 반환하도록 조정할 수 있습니다.\n",
        "\n",
        "<span id=\"create-the-directory-and-an-empty-program-file\" />\n",
        "\n",
        "### 디렉터리와 빈 프로그램 파일을 생성합니다\n",
        "\n",
        "먼저 라는 `source_files` 이름의 디렉터리를 만들고, 그 디렉터리 안에 프로그램 파일을 생성하여 경로가 가 되도록 `./source_files/transpile_remote.py`하세요. 이 파일을 Qiskit Serverless 에 업로드하시면 됩니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a9b3fb7d-abd6-4a3e-b9b1-b21202d8db6d",
      "metadata": {},
      "source": [
        "<span id=\"add-code-to-your-program-file\" />\n",
        "\n",
        "### 프로그램 파일에 코드를 추가하세요\n",
        "\n",
        "프로그램 파일에 다음 코드를 입력한 다음 저장하세요.\n",
        "\n",
        "<Admonition type=\"caution\">\n",
        "  노트북에서 코드 셀을 로컬로 실행하면 [매직 ](https://ipython.readthedocs.io/en/stable/interactive/magics.html#cellmagic-writefile)`%%writefile` 명령어가 표시됩니다. 이 마법 같은 명령어를 사용하여 셀을 실행하면, 셀이 실제로 실행되는 대신 디스크에 저장됩니다.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "214eb803-d1fa-4ac0-b955-8b24717086f4",
      "metadata": {},
      "outputs": [],
      "source": [
        "# This cell is hidden from users, it creates a new folder\n",
        "from pathlib import Path\n",
        "\n",
        "Path(\"./source_files\").mkdir(exist_ok=True)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "64722041-22ed-42bd-8d83-d8e9f5e5b55b",
      "metadata": {
        "editable": true,
        "slideshow": {
          "slide_type": ""
        },
        "tags": []
      },
      "outputs": [],
      "source": [
        "%%writefile ./source_files/transpile_remote.py\n",
        "# If you include the preceding `%%writefile` command (visible only when you read this\n",
        "# locally in a notebook), running this cell saves to disk rather than executing the code.\n",
        "\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "\n",
        "def transpile_remote(circuit, optimization_level, backend):\n",
        "    \"\"\"Transpiles an abstract circuit into an ISA circuit for a given backend.\"\"\"\n",
        "    pass_manager = generate_preset_pass_manager(\n",
        "        optimization_level=optimization_level,\n",
        "\t\tbackend=backend\n",
        "    )\n",
        "    isa_circuit = pass_manager.run(circuit)\n",
        "    return isa_circuit"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7e80b5bb-0f76-43d1-a68c-97b4b22cc88a",
      "metadata": {},
      "source": [
        "<span id=\"add-code-to-get-program-arguments\" />\n",
        "\n",
        "### 프로그램 인수를 가져오려면 코드를 추가하세요\n",
        "\n",
        "이제 프로그램 파일에 다음 코드를 추가하세요. 이 코드는 프로그램 인수를 설정합니다.\n",
        "\n",
        "이니셜 `transpile_remote.py` 에는 세 가지 입력이 있습니다: `circuits`, `backend_name`, `optimization_level` 입니다. 서버리스는 현재 직렬화 가능한 입력과 출력만 허용하도록 제한되어 있습니다. 따라서 `backend` 을 직접 전달할 수 없으므로 대신 `backend_name` 을 문자열로 사용하세요.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "6819379b-d7b2-4fda-9e6b-459eec748a79",
      "metadata": {},
      "outputs": [],
      "source": [
        "%%writefile --append ./source_files/transpile_remote.py\n",
        "# If you include the preceding `%%writefile` command (visible only when you read this\n",
        "# locally in a notebook), running this cell saves to disk rather than executing the code.\n",
        "\n",
        "from qiskit_serverless import get_arguments, save_result, distribute_task, get\n",
        "\n",
        "# Get program arguments\n",
        "arguments = get_arguments()\n",
        "circuits = arguments.get(\"circuits\")\n",
        "backend_name = arguments.get(\"backend_name\")\n",
        "optimization_level = arguments.get(\"optimization_level\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5ae9fb12-f06f-4f7d-8f37-1d872285deab",
      "metadata": {},
      "source": [
        "<span id=\"add-code-that-calls-the-backend\" />\n",
        "\n",
        "### 백엔드를 호출하는 코드를 추가하세요\n",
        "\n",
        "프로그램 파일에 다음 코드를 추가하세요. 이 코드는 런타임 서비스를 가져와 이를 사용하여 백엔드를 선택합니다.\n",
        "\n",
        "<Admonition type=\"note\" title=\"Qiskit Serverless 프로그램 내에서 get_runtime_service 사용\">\n",
        "  Qiskit Serverless 에서 실행되는 코드 내에서, 를 직접 `QiskitRuntimeService()` 인스턴스화하는 대신 ( `get_runtime_service()` 에서 가져온 `qiskit_serverless`) 를 사용하여 런타임 서비스를 생성하십시오.\n",
        "\n",
        "  `get_runtime_service()` IBM Quantum 의 모든 기본 작업과 이를 통해 실행되는 세션을 상위 Qiskit Serverless 작업에 등록하는, 해당 `QiskitRuntimeService` 작업을 둘러싼 드롭인 래퍼를 반환합니다. 이 연동 기능을 통해 플랫폼은 서버리스 작업을 해당 작업이 생성하는 QPU 작업 및 세션과 연결하여, 상태 추적, 로그 기록, 사용량 및 과금 처리를 수행할 수 있습니다. 'bare'는 플랫폼이 해당 작업을 사용자의 서버리스 작업과 절대 연결하지 않도록 작업을 `QiskitRuntimeService` 제출하므로, 두 작업 간의 연결이 끊어집니다.\n",
        "\n",
        "  모든 인수가\n",
        "  선택적입니다. 프로그램 소스 코드 내에서 권장되는 형식은 인수를 지정하지 않는 `get_runtime_service()` 것으로, 이 경우 환경에서 인증 데이터를 가져옵니다. 이 함수는 와 동일한 `channel`, `token`, `instance`, 및 `url` 인수들을 선택적으로 받아들입니다 `QiskitRuntimeService`.\n",
        "</Admonition>\n",
        "\n",
        "다음 코드는 사용자가 이미 를 사용하여 인증 정보를 저장하는 절차를 완료했다고 가정하며 `QiskitRuntimeService.save_account`, 별도로 지정하지 않는 한 저장된 기본 계정을 불러옵니다. 자세한 내용은 [‘로그인 자격 증명 저장’](/docs/guides/save-credentials) 및 [‘ IBM Quantum Compute Service 계정 초기화’를](/docs/guides/initialize-account) 참조하십시오.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "4b0c7d24-9b87-4e00-bb1d-f82aa967cb1d",
      "metadata": {},
      "outputs": [],
      "source": [
        "%%writefile --append ./source_files/transpile_remote.py\n",
        "# If you include the preceding `%%writefile` command (visible only when you read this\n",
        "# locally in a notebook), running this cell saves to disk rather than executing the code.\n",
        "\n",
        "from qiskit_serverless import get_runtime_service\n",
        "\n",
        "service = get_runtime_service()\n",
        "backend = service.backend(backend_name)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "61e7cb3b-6d62-4b68-817a-39c0c1d95a9b",
      "metadata": {},
      "source": [
        "<span id=\"add-code-to-transpile\" />\n",
        "\n",
        "### 트랜스파일할 코드 추가\n",
        "\n",
        "마지막으로, 프로그램 파일에 다음 코드를 추가하세요. 이 코드는 전달된 `circuits` 모든 값에 대해 `transpile_remote()` 실행되며, 그 `transpiled_circuits` 결과를 반환합니다:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "041e7f85-e9e8-424d-8694-d54316225cc4",
      "metadata": {},
      "outputs": [],
      "source": [
        "%%writefile --append ./source_files/transpile_remote.py\n",
        "# If you include the preceding `%%writefile` command (visible only when you read this\n",
        "# locally in a notebook), running this cell saves to disk rather than executing the code.\n",
        "\n",
        "# Each circuit is being transpiled and will populate the array\n",
        "results = [\n",
        "    transpile_remote(circuit, 1, backend)\n",
        "    for circuit in circuits\n",
        "]\n",
        "\n",
        "save_result({\n",
        "    \"transpiled_circuits\": results\n",
        "})"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dac118ab-e447-4ddd-a5f8-d13e3953db76",
      "metadata": {},
      "source": [
        "<span id=\"upload-to-qiskit-serverless\" />\n",
        "\n",
        "<span id=\"authenticate-to-qiskit-serverless\" />\n",
        "\n",
        "### Qiskit Serverless 에 인증하기\n",
        "\n",
        "API 키를 사용하여 `qiskit-ibm-catalog``QiskitServerless` 에 인증하십시오(기존 `QiskitRuntimeService` API 키를 사용하거나 [IBM Quantum Platform 대시보드]() 에서 새 API 키를 생성할 수 있습니다).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "8d1385c3-09a5-42c6-a5bc-53f686d8410e",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_ibm_catalog import QiskitServerless, QiskitFunction\n",
        "\n",
        "# Authenticate to the remote cluster and submit the pattern for remote execution\n",
        "serverless = QiskitServerless()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a0f64820-5fb1-41b9-9cb4-5095d0b5db43",
      "metadata": {},
      "source": [
        "<span id=\"run-code-to-upload\" />\n",
        "\n",
        "### 코드를 실행하여 업로드하세요\n",
        "\n",
        "프로그램을 업로드하려면 다음 코드를 실행하세요. Qiskit Serverless (이 경우 `working_dir` ) `source_files`의 내용을 로 압축한 `tar` 뒤, 이를 업로드하고 정리합니다. 는 `entrypoint`Qiskit Serverless 가 실행할 주 실행 파일을 지정합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "c1cdd46d-71e9-4711-a09b-6eca569ede6a",
      "metadata": {},
      "outputs": [],
      "source": [
        "transpile_remote_demo = QiskitFunction(\n",
        "    title=\"transpile_remote_serverless\",\n",
        "    entrypoint=\"transpile_remote.py\",\n",
        "    working_dir=\"./source_files/\",\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "8b675d04-bde8-4b3d-b9e5-99982ef742e1",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "QiskitFunction(transpile_remote_serverless)"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "serverless.upload(transpile_remote_demo)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3a840c18-3010-4d05-91cb-592e2692c1d7",
      "metadata": {},
      "source": [
        "<span id=\"verify-upload\" />\n",
        "\n",
        "### 업로드 확인\n",
        "\n",
        "업로드가 성공적으로 완료되었는지 확인하려면 다음 코드에서와 같이 를 `serverless.list()`사용하세요:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "afaa3935-adf7-4b28-a8f0-583a82bbe3f1",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "QiskitFunction(transpile_remote_serverless)"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Get program from serverless.list() that matches the title of the one we uploaded\n",
        "next(\n",
        "    program\n",
        "    for program in serverless.list()\n",
        "    if program.title == \"transpile_remote_serverless\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a416b143-6f70-49dc-ab2f-ad66f042cab1",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 다음 단계\n",
        "\n",
        "<Admonition type=\"info\" title=\"권장사항\">\n",
        "  * [‘첫 번째 Qiskit Serverless 워크로드를 원격으로](/docs/guides/serverless-run-first-workload) 실행하기’ 항목에서 입력값을 전달하고 프로그램을 원격으로 실행하는 방법을 알아보세요.\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"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}