{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "e6e50bd6-8ac4-40b1-ac0f-6e22b6af1377",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Simula un modello di Ising con kick utilizzando la funzione TEM\"\n",
        "description: \"Introduzione a TEM, una funzione Qiskit di Algorithmiq, per calcolare stime con mitigazione degli errori di post-elaborazione software utilizzando reti tensoriali.\"\n",
        "---\n",
        "\n",
        "<span id=\"simulate-a-kicked-ising-model-with-the-tem-function\" />\n",
        "\n",
        "# Simula un modello di Ising con kick utilizzando la funzione TEM\n",
        "\n",
        "{/* cspell:ignore Floquet, linestyles */}\n",
        "\n",
        "Il metodo TEM (Tensor-network Error Mitigation) di Algorithmiq è un algoritmo ibrido quantistico-classico progettato per eseguire la mitigazione del rumore interamente nella fase di post-elaborazione classica. Con il TEM, l'utente può calcolare i valori attesi degli osservabili, mitigando gli inevitabili errori indotti dal rumore che si verificano sull'hardware quantistico con maggiore precisione ed efficienza in termini di costi, rendendolo un'opzione molto interessante sia per i ricercatori quantistici che per i professionisti del settore.\n",
        "\n",
        "Questo tutorial mostra come TEM possa ottenere risultati significativi per le dinamiche di un sistema quantistico, che sarebbero inaccessibili senza la mitigazione degli errori e che richiederebbero risorse quantistiche notevolmente maggiori se si utilizzassero altri metodi di mitigazione degli errori come PEC e ZNE.\n",
        "\n",
        "*Stima di utilizzo: questo notebook utilizza circa 10 minuti QPU sui dispositivi Heron r3. Il tempo di esecuzione può dipendere in modo sostanziale dal dispositivo scelto. Di seguito sono riportate le stime di utilizzo per sezione.*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1f5e328d-fe93-4ee2-995b-2e70b36ea0de",
      "metadata": {},
      "source": [
        "<span id=\"run-error-mitigated-many-body-physics-experiments-with-the-tem-function\" />\n",
        "\n",
        "## Esegui esperimenti di fisica dei sistemi a molti corpi con mitigazione degli errori utilizzando la funzione TEM\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b63a662c-a4e9-4b5f-92fd-46352a2bd0bd",
      "metadata": {},
      "source": [
        "Questo tutorial si basa sul seguente riferimento: [L. E. Fischer et al., Nat. Fisico. (2026)](https://www.nature.com/articles/s41567-025-03144-9). Questo riferimento tratta una simulazione reale su hardware quantistico fino a 91 qubit. In questo tutorial ricreiamo una simulazione simile su un circuito di dimensioni inferiori.\n",
        "\n",
        "Il modello di Ising modificato corrisponde al modello di Ising tradizionale:\n",
        "\n",
        "$\\hat{H}_{\\text{I}} = J \\sum_{n=0}^{N-2} \\hat{Z}_n \\hat{Z}_{n+1} + h \\sum_{n=0}^{N-1} \\hat{Z}_n$\n",
        "\n",
        "a cui viene applicato un calcio trasversale:\n",
        "\n",
        "$\\hat{H}_{K} = b \\sum_{n=0}^{N-1} \\hat{X}_n$\n",
        "\n",
        "L'obiettivo è simulare le dinamiche di uno stato sotto l'Hamiltoniano di Ising con kick trasversale, la cui evoluzione temporale può essere implementata da un' $\\hat{U}_{\\text{KI}} = e^{-i \\hat{H}_K} e^{-i \\hat{H}_I} $ unitaria di Floquet. Lo stato iniziale da evolvere è quello in cui il primo qubit si trova nello stato $|+\\rangle$, mentre gli altri sono accoppiati e impostati nello stato di Bell $(|00\\rangle + |11\\rangle)/\\sqrt{2}$.\n",
        "\n",
        "La quantità che vogliamo osservare è la funzione di correlazione. [Il documento di riferimento](https://www.nature.com/articles/s41567-025-03144-9) discute come questa quantità possa essere riscritta come un operatore di Pauli di tipo \" $\\hat{X}$ \" sul qubit \" $n^{th}$ \".\n",
        "Dopo una serie di passi temporali fisici $t$, calcoliamo il valore dell'operatore di Pauli $\\hat{X}_{n=t}$.\n",
        "A seconda dei parametri del sistema, il valore di questa osservabile è uguale a un valore che può essere calcolato con esattezza o solo simulato con metodi approssimativi. Nello specifico, per $|J|=|b|=\\pi/4$ è uguale a $[\\cos(2h)]^t$, che è il valore che useremo per confrontare i risultati di questo tutorial. Inoltre, in un dato intervallo di tempo $t$, $\\langle\\hat{X}_{n\\neq t}\\rangle$ è pari a zero. Per i dettagli su come ottenere questi valori e per un confronto con i risultati approssimativi della simulazione classica al di fuori di questi parametri, si veda [L. E. Fischer et al., Nat. Fisico. (2026)](https://www.nature.com/articles/s41567-025-03144-9).\n",
        "\n",
        "Il TEM funziona caratterizzando innanzitutto il rumore per ogni singolo strato di porte a due qubit nel circuito, oltre a caratterizzare l'errore di lettura. Quindi, il circuito viene eseguito sulla macchina quantistica. Infine, la mitigazione dell'errore della rete tensoriale viene eseguita sulle risorse classiche in IBM Cloud® e viene restituito il valore mitigato. In questo esempio, il circuito presenta due livelli distinti da caratterizzare.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4b30f191-9759-49de-ba8f-7cc616b61ec6",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## Configura\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9cf6d15e-324b-474a-886c-c3dca5a24141",
      "metadata": {},
      "source": [
        "Come prerequisito, assicurarsi che siano installate le dipendenze necessarie.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "1eeec332-29ca-4882-8129-d1c93ed82b2b",
      "metadata": {},
      "outputs": [],
      "source": [
        "%pip install numpy matplotlib qiskit qiskit-ibm-catalog qiskit-ibm-runtime pylatexenc qiskit_qasm3_import"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "ad0002b7-dbff-4699-af52-ba0df72ed200",
      "metadata": {},
      "outputs": [],
      "source": [
        "import os\n",
        "from matplotlib import pyplot as plt\n",
        "import numpy as np\n",
        "\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.qasm3 import load\n",
        "\n",
        "from qiskit_ibm_catalog import QiskitFunctionsCatalog"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b95b9e75-37fe-4f86-a923-0a833c7960f8",
      "metadata": {},
      "source": [
        "<span id=\"error-mitigation-with-tem\" />\n",
        "\n",
        "## Mitigazione degli errori con TEM\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "651a3f04-c8ba-4a39-8415-52d7e313ba2a",
      "metadata": {},
      "source": [
        "Qui forniamo un circuito che implementa il modello di Ising con kick descritto sopra. Il circuito è preparato come segue. In primo luogo, vi è una fase di preparazione dello stato, in cui il primo qubit si trova nello stato $|+\\rangle$, mentre gli altri sono in coppie di Bell $(|00\\rangle + |11\\rangle)/\\sqrt{2}$. Segue la struttura a mattoni che implementa l'evoluzione unitaria $\\hat{U}_{\\text{KI}}$. Il numero di passi temporali fisici corrisponde agli strati del circuito $t/2$.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "11e42656-76ba-452c-af22-8f4cd22ff174",
      "metadata": {},
      "source": [
        "Il codice seguente scarica i due file QASM necessari per questo tutorial.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "39bf7188-3771-4994-a6c6-e9cfcae3484f",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Download required QASM files\n",
        "import urllib\n",
        "\n",
        "urllib.request.urlretrieve(\n",
        "    \"https://ibm.box.com/shared/static/swy5jtq309b0xpzluzlmsmj908yphes8.qasm\",\n",
        "    \"ki_30q.qasm\",\n",
        ")\n",
        "urllib.request.urlretrieve(\n",
        "    \"https://ibm.box.com/shared/static/et3gkodonw6gsp2trs43lzaozrdtiu7s.qasm\",\n",
        "    \"ki_12q.qasm\",\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1f6f9970-63fb-40f4-9586-261cba23cb88",
      "metadata": {},
      "source": [
        "Possiamo visualizzare una versione ridotta del circuito, con 12 qubit e sei intervalli di tempo:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "381a4e25-bc9c-47d0-b9f1-172eb5516484",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/simulate-kicked-ising-tem/extracted-outputs/381a4e25-bc9c-47d0-b9f1-172eb5516484-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Parameters of the kicked Ising model\n",
        "h = 0.0\n",
        "num_qubits = 12\n",
        "t_steps = 6\n",
        "\n",
        "# Load the circuit for the kicked Ising model\n",
        "small_circuit = load(\"ki_12q.qasm\")\n",
        "\n",
        "# Draw the circuit\n",
        "small_circuit.draw(\"mpl\", scale=0.25, fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a674e407-504d-4812-82bf-98e91ec9a4b4",
      "metadata": {},
      "source": [
        "Successivamente, crea l'osservabile, $\\hat{X}_{n=t}$. È costruito come una semplice stringa di Pauli con l'ordine corrispondente a quello utilizzato da Qiskit:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "a9a87f6c-176d-4c85-85e5-6751aea0c90b",
      "metadata": {},
      "outputs": [],
      "source": [
        "def xt_observable(n_qubits, t_steps):\n",
        "    pauli_str = \"\".join([\"I\" * t_steps, \"X\", \"I\" * (n_qubits - t_steps - 1)])\n",
        "    pauli_str = pauli_str[::-1]  # Reverse the string to match qiskit order\n",
        "    return SparsePauliOp(data=pauli_str, coeffs=1.0)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ba5f7042-4abd-4ae7-a091-591678377e8f",
      "metadata": {},
      "source": [
        "Nel nostro piccolo esempio a 12 qubit, l'osservabile appare così:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "b2608df1-b4e4-4143-bea5-a65ab8045fd4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "SparsePauliOp(['IIIIIXIIIIII'],\n",
            "              coeffs=[1.+0.j])\n"
          ]
        }
      ],
      "source": [
        "# Build the observable for the kicked Ising model\n",
        "small_observable = xt_observable(n_qubits=12, t_steps=6)\n",
        "print(small_observable)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e588fafe-8db8-4445-8893-a78190b27b64",
      "metadata": {},
      "source": [
        "Qiskit Functions utilizzare i PUB come mezzo per raccogliere i contributi. Nel nostro caso, consideriamo un singolo circuito e un osservabile come nostro PUB :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "fc48eb54-148b-4b0d-8424-a135cb92039e",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Collect the input PUBs, in this case composed of a\n",
        "# single circuit and observable\n",
        "pubs = [(small_circuit, [small_observable])]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9a4bcd8d-ae21-40ab-b0e2-510236ba92de",
      "metadata": {},
      "source": [
        "Successivamente, abbiamo accesso alla funzione TEM. Per prima cosa impostiamo l'autenticazione richiesta su IBM Cloud e selezioniamo un backend dai dispositivi disponibili. Il token, i backend disponibili e i nomi delle risorse cloud corrispondenti (CRN) possono essere ottenuti accedendo al proprio account sulla [dashboard](/) IBM Quantum Platform.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "6c9f80a8-4a65-4daa-94bb-a98edd6a1989",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Set IBM Quantum credentials and backend configuration\n",
        "personal_token = os.environ.get(\n",
        "    \"QISKIT_IBM_TOKEN\", \"<API-KEY>\"\n",
        ")  # Replace with your personal token or set the environment variable\n",
        "channel = \"ibm_quantum_platform\"\n",
        "crn = \"your_crn\"  # Replace with the Cloud Resource Name (CRN)\n",
        "\n",
        "# Select the QPU backend\n",
        "backend_name = \"ibm_qpu_name\"  # Replace with your desired backend's name"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "10df1803-5245-42b2-8eea-c0773cd655b6",
      "metadata": {},
      "source": [
        "Caricare la funzione TEM dall' [Qiskit Functions Catalog](/functions) (Libreria di funzioni di calcolo):\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "2473b284-108f-45fe-a8d8-3aed584137f6",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Load the TEM function from the Qiskit Functions Catalog\n",
        "catalog = QiskitFunctionsCatalog(\n",
        "    channel=channel,\n",
        "    token=personal_token,\n",
        "    instance=crn,\n",
        ")\n",
        "tem = catalog.load(\"algorithmiq/tem\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3c732819-4dca-421c-bc2b-45ff5a5912db",
      "metadata": {},
      "source": [
        "Ora possiamo eseguire un esperimento sul circuito Ising avviato con la mitigazione degli errori fornita dal TEM. Utilizzando le impostazioni predefinite, TEM può essere eseguito in modo semplice con un tempo di esecuzione QPU previsto di circa 2.5 minuti, a seconda della QPU:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "b826e025-f36b-4fb5-90bd-e1ef36f5c1b2",
      "metadata": {},
      "outputs": [],
      "source": [
        "tem_job = tem.run(pubs=pubs, backend_name=backend_name)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4b692a80-5a10-4131-9d7f-785fedbe4221",
      "metadata": {},
      "source": [
        "Con le opzioni predefinite, la funzione TEM esegue tre operazioni sul computer quantistico: apprendimento del rumore, mitigazione della lettura e campionamento dei circuiti. Il numero di scatti utilizzati da ciascuno di questi può essere modificato nelle opzioni passate alla funzione. Per impostazione predefinita, questi parametri sono configurati per ottenere una precisione dell' 0.05 e nei valori attesi mitigati.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "25b6f313-a928-493e-837f-45e6e7836aef",
      "metadata": {},
      "source": [
        "Puoi controllare lo stato del tuo lavoro sulla [dashboard](/) di IBM Quantum Platform o con:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "05e202ff-5b86-4a93-a693-86fbb1cf3e02",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "QUEUED\n"
          ]
        }
      ],
      "source": [
        "print(tem_job.status())"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8e427c75-72fb-4a97-b723-97d695a692d3",
      "metadata": {},
      "source": [
        "Quando lo stato è `DONE`, possiamo controllare i risultati grezzi e mitigati. I valori `tem_evs` definiti di seguito sono i valori attesi degli osservabili richiesti, in questo caso un solo osservabile, $\\langle \\hat X_{n=t}\\rangle$, e `tem_std` sono le deviazioni standard corrispondenti.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "3ca34069-1363-4e37-9718-91639d817a82",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "TEM Result: 1.031 ± 0.046\n"
          ]
        }
      ],
      "source": [
        "# Get the results of the TEM job\n",
        "tem_results = tem_job.result()[\n",
        "    0\n",
        "]  # Get the first and only result from the job\n",
        "tem_evs = tem_results.data.evs[0]\n",
        "tem_std = tem_results.data.stds[0]\n",
        "\n",
        "print(f\"TEM Result: {tem_evs:.3f} ± {tem_std:.3f}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f90f503e-ab80-4550-a7cf-dfeea12babb0",
      "metadata": {},
      "source": [
        "È inoltre possibile verificare quanto tempo di esecuzione quantistico è stato utilizzato per ciascuna chiamata all'indirizzo [IBM Quantum Platform]() o ispezionando i metadati dei risultati dal codice Python.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "b05818d6-b680-483e-9084-f3fd2de067ab",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "TEM Runtime: 155.0 seconds\n"
          ]
        }
      ],
      "source": [
        "# Get the TEM job runtime\n",
        "tem_runtime = tem_job.result().metadata[\"resource_usage\"][\n",
        "    \"RUNNING: EXECUTING_QPU\"\n",
        "][\"QPU_TIME\"]\n",
        "\n",
        "print(f\"TEM Runtime: {tem_runtime} seconds\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6be333a8-41c9-4ba9-b07d-a0ac50149add",
      "metadata": {},
      "source": [
        "<span id=\"customize-tem-parameters-and-advanced-options\" />\n",
        "\n",
        "## Personalizza i parametri TEM e le opzioni avanzate\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "abee6fc2-90d6-4608-ad21-c606c936dd94",
      "metadata": {},
      "source": [
        "La funzione TEM offre diverse opzioni avanzate per personalizzare il flusso di lavoro di mitigazione degli errori. Queste opzioni consentono di controllare la precisione, il numero di scatti, le strategie di apprendimento del rumore e altri parametri per adattarsi meglio ai requisiti dell'esperimento e alle risorse quantistiche disponibili.\n",
        "\n",
        "Le opzioni avanzate più comuni sono:\n",
        "\n",
        "* **`precision`**: Specificare la precisione desiderata per i valori attesi mitigati.\n",
        "* **`default_shots`**: Invece di `precision`, è possibile specificare il numero di scatti utilizzati dal lavoro di misurazione.\n",
        "* **`tem_max_bond_dimension`**: La dimensione massima del legame utilizzata nella rete tensoriale.\n",
        "* **`tem_compression_cutoff`**: Il valore di cutoff da utilizzare per la rete tensoriale.\n",
        "* **Opzioni di apprendimento del rumore** : configurare le caratteristiche del rumore, come il numero di ripetizioni o circuiti di calibrazione specifici.\n",
        "* **`private`**: Assicurati che i circuiti e i risultati degli esperimenti rimangano privati e disabilita il download multiplo dei risultati dei lavori.\n",
        "\n",
        "Per un elenco completo delle opzioni supportate e delle relative descrizioni, consultare la [documentazione TEM](/docs/guides/algorithmiq-tem) o il sito [Qiskit Functions Catalog](/functions). È possibile regolare questi parametri per bilanciare il tempo di esecuzione, l'utilizzo delle risorse e l'accuratezza dei risultati.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "24db681c-b306-41e0-8507-626ef279b076",
      "metadata": {},
      "source": [
        "È possibile passare queste opzioni come dizionario `options` all'argomento quando si esegue la funzione TEM:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a2e9a032-91cb-4a18-9a00-00a149e60459",
      "metadata": {},
      "outputs": [],
      "source": [
        "options = {\n",
        "    \"default_shots\": 10_000,\n",
        "    \"tem_max_bond_dimension\": 512,\n",
        "    \"tem_compression_cutoff\": 1e-16,\n",
        "    # This option helps optimizing the measurement\n",
        "    # stage since the observable is strongly biased\n",
        "    # toward the X operator for all the qubits.\n",
        "    \"compute_shadows_bias_from_observable\": True,\n",
        "    # set to True to keep experiment results private,\n",
        "    # recommended for confidential circuits\n",
        "    \"private\": False,\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "db700868-4dae-48c8-be1a-668ef2e63177",
      "metadata": {},
      "source": [
        "È inoltre possibile specificare opzioni personalizzate per il modello di apprendimento del rumore. Seguono le definizioni utilizzate nel : `qiskit-ibm-runtime`[`NoiseLearnerOptions`](/docs/api/qiskit-ibm-runtime/options-noise-learner-options)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 29,
      "id": "30591014-3bc6-4548-ba0d-dc5cc22e9dcc",
      "metadata": {},
      "outputs": [],
      "source": [
        "nl_options = {\n",
        "    \"num_randomizations\": 32,\n",
        "    \"max_layers_to_learn\": 2,\n",
        "    \"shots_per_randomization\": 128,\n",
        "    \"layer_pair_depths\": [0, 1, 2, 4, 16, 32],\n",
        "}\n",
        "\n",
        "# add noise learning options to the overall options\n",
        "options |= nl_options"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "216ad12c-8c70-4073-8515-b07fd57f74d4",
      "metadata": {},
      "source": [
        "Ripeti l'esperimento con queste opzioni personalizzate ottimizzate per il nostro circuito. Il tempo di esecuzione previsto è di circa quattro minuti QPU.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "id": "ebce8e14-433f-4858-96c6-9d90ff0353af",
      "metadata": {},
      "outputs": [],
      "source": [
        "tem_job_custom = tem.run(\n",
        "    pubs=pubs, backend_name=backend_name, options=options\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bd8d2c12-c9da-4ac3-97c0-d53be1455091",
      "metadata": {},
      "source": [
        "Se il lavoro non è impostato come privato, possiamo recuperare il risultato in un secondo momento. Per farlo, salva l'ID del lavoro stampato qui e usa `tem_job_custom = catalog.get_job_by_id(\"your-job-id\")`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "0f99101b-9e72-45c8-8b00-9f3a257b8b3b",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID: 1ba10094-a541-457a-9287-dbd49306d12d\n"
          ]
        }
      ],
      "source": [
        "job_id = tem_job_custom.job_id\n",
        "print(f\"Job ID: {job_id}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "id": "0c751dac-e856-4371-aaed-f67aca31061f",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "TEM Result: 0.956 ± 0.018\n"
          ]
        }
      ],
      "source": [
        "results_custom = tem_job_custom.result()\n",
        "tem_evs = results_custom[0].data.evs[0]\n",
        "tem_std = results_custom[0].data.stds[0]\n",
        "\n",
        "print(f\"TEM Result: {tem_evs:.3f} ± {tem_std:.3f}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "edfef6f9-6bac-42bb-8bd2-95f977f7b31b",
      "metadata": {},
      "source": [
        "Ora possiamo esaminare i risultati e i metadati per ottenere informazioni dettagliate sull'esperimento:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "id": "dd189b2d-860b-4b9a-88c2-7e5c62b1f160",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Unmitigated Result: 0.894 ± 0.015\n",
            "Exact Result: 1.0\n"
          ]
        }
      ],
      "source": [
        "metadata_custom = results_custom[0].metadata\n",
        "\n",
        "unmitigated_evs = metadata_custom[\"evs_non_mitigated\"][0]\n",
        "unmitigated_stds = metadata_custom[\"stds_non_mitigated\"][0]\n",
        "print(f\"Unmitigated Result: {unmitigated_evs:.3f} ± {unmitigated_stds:.3f}\")\n",
        "\n",
        "# Exact result for the kicked Ising model from the reference paper\n",
        "exact_evs = np.cos(2 * h) ** t_steps\n",
        "print(\"Exact Result:\", exact_evs)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 35,
      "id": "c3a2168d-98df-491e-a1f8-05de5684ab96",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/simulate-kicked-ising-tem/extracted-outputs/c3a2168d-98df-491e-a1f8-05de5684ab96-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Plot comparing the different expectation values\n",
        "plt.bar(\n",
        "    [\"Unmitigated\", \"TEM\"],\n",
        "    [unmitigated_evs, tem_evs],\n",
        "    yerr=[unmitigated_stds, tem_std],\n",
        "    color=[\"grey\", \"c\"],\n",
        ")\n",
        "plt.hlines(y=exact_evs, xmin=-0.5, xmax=1.5, colors=\"r\", linestyles=\"dashed\")\n",
        "plt.ylabel(\"Expectation Value\")\n",
        "plt.ylim(0, 1.1)\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d643bdb4-22e0-4f55-b3a8-d5ef39f6e696",
      "metadata": {},
      "source": [
        "Infine, possiamo verificare l'impatto delle opzioni personalizzate sulla QPU e sul runtime classico:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "09cf2226-c48c-483b-aa49-80186229ae95",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "QPU Runtime: 342.0 seconds\n",
            "Classical Runtime: 107.632604 seconds\n"
          ]
        }
      ],
      "source": [
        "# Get the metadata of the TEM job\n",
        "job_metadata = results_custom.metadata\n",
        "\n",
        "# Get the runtime of the TEM job\n",
        "qpu_runtime = job_metadata[\"resource_usage\"][\"RUNNING: EXECUTING_QPU\"][\n",
        "    \"QPU_TIME\"\n",
        "]\n",
        "classical_runtime = (\n",
        "    job_metadata[\"resource_usage\"][\"RUNNING: OPTIMIZING_FOR_HARDWARE\"][\n",
        "        \"CPU_TIME\"\n",
        "    ]\n",
        "    + job_metadata[\"resource_usage\"][\"RUNNING: POST_PROCESSING\"][\"CPU_TIME\"]\n",
        ")\n",
        "\n",
        "print(f\"QPU Runtime: {qpu_runtime} seconds\")\n",
        "print(f\"Classical Runtime: {classical_runtime} seconds\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7cea6cf1-5530-4bf6-83da-ad2e9ff96806",
      "metadata": {},
      "source": [
        "<span id=\"scale-tem-to-large-circuits\" />\n",
        "\n",
        "## Scala TEM per circuiti di grandi dimensioni\n",
        "\n",
        "I circuiti di grandi dimensioni possono, in linea di principio, essere gestiti con la funzione TEM. Tuttavia, è importante essere consapevoli dei limiti delle risorse classiche, poiché il TEM viene eseguito su runner dell' IBM Cloud con tempi di esecuzione potenzialmente molto lunghi. Per circuiti di dimensioni estremamente grandi, contattare il team di assistenza TEM all'indirizzo [qiskit\\ \\_ibm@algorithmiq.fi](mailto:qiskit_ibm@algorithmiq.fi).\n",
        "\n",
        "Qui eseguiamo un esempio con un circuito più grande, di dimensioni pari a quelle utilizzate su scala industriale, da 30 qubit, ottimizzando i parametri TEM in termini di velocità piuttosto che di precisione.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f7ea1d3c-d745-48cc-8922-b070b2b5fd44",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Kicked Ising model parameters\n",
        "n_qubits = 30\n",
        "t_steps = 15\n",
        "h = 0.0\n",
        "\n",
        "# Load the circuit for the kicked Ising model\n",
        "circuit = load(\"ki_30q.qasm\")\n",
        "\n",
        "\n",
        "# Build the observable for the kicked Ising model\n",
        "observable = xt_observable(n_qubits=n_qubits, t_steps=t_steps)\n",
        "\n",
        "# Collect the input PUBs, in this case composed of a\n",
        "# single circuit and observable\n",
        "pubs = [(circuit, [observable])]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "854c3208-8c0f-4f7d-b260-0abba2bc71a0",
      "metadata": {},
      "source": [
        "Definiamo alcune opzioni orientate alle prestazioni:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 49,
      "id": "64882a71-3027-4e25-b714-9e9d6b13cd49",
      "metadata": {},
      "outputs": [],
      "source": [
        "options = {\n",
        "    \"num_randomizations\": 32,\n",
        "    \"max_layers_to_learn\": 2,\n",
        "    \"shots_per_randomization\": 128,\n",
        "    \"layer_pair_depths\": [0, 1, 2, 4, 16, 32, 64],\n",
        "    \"default_shots\": 5_000,\n",
        "    \"tem_max_bond_dimension\": 128,\n",
        "    \"tem_compression_cutoff\": 1e-10,\n",
        "    \"compute_shadows_bias_from_observable\": True,\n",
        "    \"private\": False,\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4ba36257-1974-4274-b04c-6daf3afe9d72",
      "metadata": {},
      "source": [
        "Infine, esegui l'esperimento, ottieni il risultato e visualizzalo. Ciò richiederà circa 3.5 minuti QPU.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 50,
      "id": "6faf7f80-dec9-49d2-80e7-d4e6fdea5100",
      "metadata": {},
      "outputs": [],
      "source": [
        "tem_job_large = tem.run(pubs=pubs, backend_name=backend_name, options=options)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 51,
      "id": "333b2335-b480-4bf9-854c-5155eedee900",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Job ID: 9f3f190f-f4b0-4dcb-bb83-5f71f37d0d77\n"
          ]
        }
      ],
      "source": [
        "job_id = tem_job_large.job_id\n",
        "print(f\"Job ID: {job_id}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 53,
      "id": "a04dd421-a212-473c-a8a9-4c8edcfc3667",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "TEM Result: 0.794 ± 0.026\n",
            "QPU Runtime: 203.0 seconds\n",
            "Classical Runtime: 251.71805499999996 seconds\n"
          ]
        }
      ],
      "source": [
        "results_large = tem_job_large.result()\n",
        "tem_evs = results_large[0].data.evs[0]\n",
        "tem_std = results_large[0].data.stds[0]\n",
        "\n",
        "print(f\"TEM Result: {tem_evs:.3f} ± {tem_std:.3f}\")\n",
        "\n",
        "\n",
        "# Get the metadata of the TEM job\n",
        "job_metadata = tem_job_large.result().metadata\n",
        "\n",
        "# Get the runtime of the TEM job\n",
        "qpu_runtime = job_metadata[\"resource_usage\"][\"RUNNING: EXECUTING_QPU\"][\n",
        "    \"QPU_TIME\"\n",
        "]\n",
        "classical_runtime = (\n",
        "    job_metadata[\"resource_usage\"][\"RUNNING: OPTIMIZING_FOR_HARDWARE\"][\n",
        "        \"CPU_TIME\"\n",
        "    ]\n",
        "    + job_metadata[\"resource_usage\"][\"RUNNING: POST_PROCESSING\"][\"CPU_TIME\"]\n",
        ")\n",
        "\n",
        "print(f\"QPU Runtime: {qpu_runtime} seconds\")\n",
        "print(f\"Classical Runtime: {classical_runtime} seconds\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 54,
      "id": "24894c44-e399-4b9d-a3ff-38a28ff32ece",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/simulate-kicked-ising-tem/extracted-outputs/24894c44-e399-4b9d-a3ff-38a28ff32ece-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Plot comparing the different expectation values\n",
        "metadata_large = results_large[0].metadata\n",
        "unmitigated_evs = metadata_large[\"evs_non_mitigated\"][0]\n",
        "unmitigated_stds = metadata_large[\"stds_non_mitigated\"][0]\n",
        "\n",
        "exact_evs = np.cos(2 * h) ** t_steps\n",
        "\n",
        "plt.bar(\n",
        "    [\"Unmitigated\", \"TEM\"],\n",
        "    [unmitigated_evs, tem_evs],\n",
        "    yerr=[unmitigated_stds, tem_std],\n",
        "    color=[\"grey\", \"c\"],\n",
        ")\n",
        "plt.hlines(y=exact_evs, xmin=-0.5, xmax=1.5, colors=\"r\", linestyles=\"dashed\")\n",
        "plt.ylabel(\"Expectation Value\")\n",
        "plt.ylim(0, 1.1)\n",
        "plt.show()"
      ]
    },
    {
      "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": 600
  },
  "nbformat": 4,
  "nbformat_minor": 4
}