{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "ce3d197d-7b14-4c60-8d39-a202146d0663",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Ingressi e uscite dell'esecutore\"\n",
        "description: \"Comprendere gli input e gli output della primitiva Executor.\"\n",
        "---\n",
        "\n",
        "<span id=\"executor-inputs-and-outputs\" />\n",
        "\n",
        "# Ingressi e uscite dell'esecutore\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "44219323-9419-471a-86c4-488ef0162420",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "{/*\n",
        "  DO NOT EDIT THIS CELL!!!\n",
        "  This cell's content is generated automatically by a script. Anything you add\n",
        "  here will be removed next time the notebook is run. To add new content, create\n",
        "  a new cell before or after this one.\n",
        "  */}\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Versioni del pacchetto\">\n",
        "    Il codice presente in questa pagina è stato sviluppato sulla base dei seguenti requisiti.\n",
        "    Si consiglia di utilizzare queste versioni o quelle più recenti.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.4.0\n",
        "    qiskit-ibm-runtime~=0.46.1\n",
        "    samplomatic~=0.18.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "43c044dc-259d-4759-b6a7-a05bd9d3667f",
      "metadata": {},
      "source": [
        "La primitiva Executor fa parte del [modello di esecuzione diretta](/docs/guides/directed-execution-model), che offre maggiore flessibilità nella personalizzazione di un flusso di lavoro per la mitigazione degli errori.\n",
        "\n",
        "Gli ingressi e le uscite della primitiva Executor sono molto diversi da quelli delle primitive [Sampler](/docs/guides/sampler-input-output) ed [Estimator](/docs/guides/estimator-input-output). Ad esempio, invece di accettare come input un elenco di PUB, Executor accetta un `QuantumProgram`, che contiene un elenco di `QuantumProgramItem` oggetti. Queste classi di contenitori offrono una maggiore flessibilità rispetto a un « PUB », che è una semplice struttura dati di tipo tupla.\n",
        "\n",
        "L'output di Executor è un `QuantumProgramResult`, che è un oggetto iterabile e contiene un elemento per ogni input `QuantumProgramItem`.\n",
        "\n",
        "<span id=\"programs\" />\n",
        "\n",
        "<span id=\"inputs-quantum-programs\" />\n",
        "\n",
        "## Input: programmi Quantum\n",
        "\n",
        "Come già detto, l'input di una primitiva Executor è un [`QuantumProgram`](/docs/api/qiskit-ibm-runtime/quantum-program-quantum-program), ovvero un iterabile di\n",
        "[`QuantumProgramItem`](/docs/api/qiskit-ibm-runtime/quantum-program-quantum-program-item) oggetti.  Questi oggetti possono essere di due tipi:\n",
        "\n",
        "* `CircuitItem`, che in genere contiene un circuito e i valori dei suoi parametri (se presenti).\n",
        "* `SamplexItem`, che in genere contiene le seguenti informazioni:\n",
        "  * Un circuito modello\n",
        "  * Un oggetto Samplex, utilizzato per generare insiemi casuali di parametri in fase di esecuzione (ad esempio per eseguire operazioni di twirling o per introdurre rumore)\n",
        "  * Argomenti per il samplex, che potrebbero includere i valori dei parametri del circuito originale\n",
        "\n",
        "Ciascuna di queste voci rappresenta un compito diverso che Executor deve svolgere.\n",
        "\n",
        "<span id=\"before-you-begin\" />\n",
        "\n",
        "### Prima di iniziare\n",
        "\n",
        "Alcuni degli esempi di codice presenti in questa pagina utilizzano `samplex`, che fa parte del pacchetto Samplomatic.  Pertanto, prima di eseguire quei blocchi di codice, è necessario installare Samplomatic, come illustrato nel blocco di codice seguente.  Per ulteriori informazioni, consultare la [documentazione di Samplomatic](https://qiskit.github.io/samplomatic).\n",
        "\n",
        "```python\n",
        "pip install samplomatic\n",
        "\n",
        "# For visualization support, include the visualization dependencies.\n",
        "# pip install samplomatic[vis]\n",
        "```\n",
        "\n",
        "<span id=\"example-create-a-quantumprogram-with-two-different-tasks\" />\n",
        "\n",
        "### Esempio: creare un `QuantumProgram` con due attività diverse\n",
        "\n",
        "Inizia inizializzando il tuo programma quantistico, quindi aggiungi elementi al programma utilizzando o `append_samplex_item``append_circuit_item` (se è presente un samplex), come mostrato negli esempi seguenti.\n",
        "\n",
        "La cella seguente inizializza una variabile `QuantumProgram` e specifica che devono essere eseguiti 1024 test per ogni configurazione di ciascun elemento del programma.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  A differenza di Sampler, un `QuantumProgram` accetta solo un singolo valore di campionamento. `QuantumProgram`Se desideri un valore di esposizione diverso, ti servirà un'altra foto, il che comporterebbe un lavoro a parte.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "81fc7c9e-2cc9-416a-b3d5-74f45eab48fc",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit_ibm_runtime.quantum_program import QuantumProgram\n",
        "from qiskit_ibm_runtime import Executor, QiskitRuntimeService\n",
        "from qiskit.circuit import Parameter, QuantumCircuit\n",
        "import numpy as np\n",
        "from samplomatic import build\n",
        "from samplomatic.transpiler import generate_boxing_pass_manager\n",
        "\n",
        "# Initialize an empty program\n",
        "program = QuantumProgram(shots=1024)\n",
        "\n",
        "# Initialize and transpile a 3-qubit quantum circuit with 2 parameters.\n",
        "circuit = QuantumCircuit(3)\n",
        "circuit.h(0)\n",
        "circuit.cx(0, 1)\n",
        "circuit.cx(1, 2)\n",
        "circuit.rz(Parameter(\"theta\"), 0)\n",
        "circuit.rz(Parameter(\"phi\"), 1)\n",
        "\n",
        "# `measure_all` adds a 3-bit classical register named \"meas\"\n",
        "circuit.measure_all()\n",
        "\n",
        "# Choose the least busy backend\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(operational=True, simulator=False)\n",
        "\n",
        "# Generate a preset pass manager\n",
        "# This will be used to convert the abstract circuit to an\n",
        "# equivalent Instruction Set Architecture (ISA) circuit.\n",
        "preset_pass_manager = generate_preset_pass_manager(\n",
        "    backend=backend, optimization_level=0\n",
        ")\n",
        "\n",
        "# Transpile the circuit\n",
        "isa_circuit = preset_pass_manager.run(circuit)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a1cc6580-3f31-4322-b0ea-f6bcf032a872",
      "metadata": {},
      "source": [
        "<span id=\"append-a-circuititem\" />\n",
        "\n",
        "### Aggiungi un `CircuitItem`\n",
        "\n",
        "Successivamente, aggiungere il circuito di destinazione, che è stato transpilato in base all'architettura del set di istruzioni (ISA) del backend, al file `QuantumProgram`. Poiché questo circuito ha due parametri, dobbiamo anche specificarne i valori (10 coppie in questo esempio). L'esecuzione di questa operazione `CircuitItem` è la prima attività che il programma eseguirà.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "e6f6762f-1627-450a-b74b-96ad4a3b1c9c",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Append the transpiled circuit and an array\n",
        "# containing 10 sets of parameter values to the program\n",
        "program.append_circuit_item(\n",
        "    isa_circuit,\n",
        "    circuit_arguments=np.random.rand(\n",
        "        10, 2\n",
        "    ),  # 10 sets of parameter values and 2 parameters\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "96f9ac43-8ce4-4389-bff4-5bd68b799974",
      "metadata": {},
      "source": [
        "<span id=\"append-a-samplexitem\" />\n",
        "\n",
        "### Aggiungi un `SamplexItem`\n",
        "\n",
        "Le operazioni del circuito vengono eseguite senza alcun tipo di casualità. Al contrario, gli elementi samplex consentono di specificare come randomizzare il loro contenuto. La cella successiva utilizza la `generate_boxing_pass_manager()` funzione per raggruppare i gate e le misurazioni del circuito in riquadri e aggiungere un'annotazione rotante a ciascun riquadro. Genera quindi uno schema circuitale e una coppia di campioni utilizzando la `build()` funzione.\n",
        "\n",
        "L'esecuzione di questa operazione `SamplexItem` è la seconda attività che il programma svolgerà.\n",
        "\n",
        "Per ulteriori dettagli su `samplex` e i suoi argomenti, consultare la documentazione [dell'API](https://github.com/Qiskit/samplomatic/) di Samplomatic. Per informazioni sull'uso della `generate_boxing_pass_manager()` funzione, consultare la [guida](https://qiskit.github.io/samplomatic/guides/transpiler.html) di Samplomatic Transpiler.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "4ac19f46-226b-4b13-b278-1e39e719484b",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "TensorInterface(<\n",
            "  - 'parameter_values' <float64[2]>: Input parameter values to use during sampling.\n",
            ">)\n"
          ]
        }
      ],
      "source": [
        "# Transpile the circuit, additionally grouping gates and measurements into annotated boxes\n",
        "preset_pass_manager = generate_preset_pass_manager(\n",
        "    backend=backend, optimization_level=0\n",
        ")\n",
        "\n",
        "# Use the boxing pass manager to group gates\n",
        "# and measurements into boxes and add\n",
        "# a`Twirl` annotation.\n",
        "preset_pass_manager.post_scheduling = generate_boxing_pass_manager(\n",
        "    # Add gate twirling\n",
        "    enable_gates=True,\n",
        "    # Add measurement twirling\n",
        "    enable_measures=True,\n",
        ")\n",
        "boxed_circuit = preset_pass_manager.run(circuit)\n",
        "\n",
        "# Build the template circuit and the samplex.  The template circuit has parametric gates\n",
        "# without fixed values and the samplex randomly generates the parameter\n",
        "# values on the server side at runtime to perform twirling.\n",
        "template_circuit, samplex = build(boxed_circuit)\n",
        "\n",
        "# Determine what arguments are required by the samplex.\n",
        "# Input the arguments in samplex_arguments.\n",
        "print(samplex.inputs())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "0e3b4d3d-12ea-47f2-a605-b64eed03cf95",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Append the template circuit and samplex as a samplex item\n",
        "program.append_samplex_item(\n",
        "    template_circuit,\n",
        "    samplex=samplex,\n",
        "    samplex_arguments={\n",
        "        # the arguments required by the samplex.sample method\n",
        "        \"parameter_values\": np.random.rand(10, 2),\n",
        "    },\n",
        "    shape=(28, 10),  # 28 randomizations and 10 sets of parameter values\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "eb850401-3d4f-4fac-8965-fb9ac4827ebd",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Initialize an Executor with the default options\n",
        "executor = Executor(mode=backend)\n",
        "\n",
        "# Submit the job\n",
        "job = executor.run(program)\n",
        "\n",
        "# Retrieve the result\n",
        "result = job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "541f5d2d-b974-4ae5-81e0-ef2b6e1dbe82",
      "metadata": {},
      "source": [
        "<span id=\"outputs\" />\n",
        "\n",
        "## Output\n",
        "\n",
        "Il risultato di Executor è un [`QuantumProgramResult`](/docs/api/qiskit-ibm-runtime/results-quantum-program-result), che è un iterabile. Contiene una voce per ogni dato `QuantumProgramItem` immesso, nello stesso ordine in cui sono stati inseriti. Ciascuna di queste voci di output è un dizionario in cui le chiavi sono stringhe che corrispondono ai nomi dei registri classici presenti nei circuiti di input (tra gli altri); pertanto, non è più necessario memorizzare questi nomi come si faceva con l'output del Sampler. I valori del dizionario sono di tipo `np.ndarray`.\n",
        "\n",
        "Il risultato dell'esempio precedente contiene i seguenti elementi:\n",
        "\n",
        "<span id=\"circuititem-result\" />\n",
        "\n",
        "### `CircuitItem` risultato\n",
        "\n",
        "La prima voce riporta i risultati dell'esecuzione della prima attività (a `CircuitItem`) del programma. Contiene una sola chiave, `meas`, che è il nome del registro classico nel circuito di ingresso. Il valore di questa chiave corrisponde a un array `np.ndarray` di forma `(parameter sets, shots, register bits)`, che nell'esempio sopra riportato è (10, 1024, 3).\n",
        "\n",
        "Il codice seguente mostra come accedere a queste informazioni:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "d652d69a-7a4e-4e5c-8469-97cb9ec92010",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Result shape: (10, 1024, 3)\n"
          ]
        }
      ],
      "source": [
        "# Access the results of the classical register of task #0, a CircuitItem\n",
        "result_0 = result[0][\"meas\"]\n",
        "print(f\"Result shape: {result_0.shape}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7185353a-e7a0-4bb2-b605-664184e684ed",
      "metadata": {},
      "source": [
        "<span id=\"samplexitem-result\" />\n",
        "\n",
        "### `SamplexItem` risultato\n",
        "\n",
        "La seconda voce contiene i risultati dell'esecuzione della seconda attività (a `SamplexItem`) del programma. Questo articolo contiene più chiavi. La `meas` chiave, che corrisponde al nome del registro classico del circuito di ingresso, rimanda alla matrice dei risultati di quel registro. Questo array ha la forma `(randomizations, parameter sets, shots, classical bits)`, ovvero (28, 10, 1024, 3) in questo esempio. Inoltre, l'output contiene una `measurement_flips.meas` chiave che rappresenta le correzioni di inversione di bit necessarie per annullare la rotazione della misurazione per il `meas` registro.  In questo esempio, la dimensione dell'output sarà (28, 10, 1, 3) poiché è sufficiente un solo passaggio per eseguire il bit-flip.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "884af6e2-614a-4b18-83dc-04505ddbc488",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Result shape: (28, 10, 1024, 3)\n",
            "Bit-flip corrections shape: (28, 10, 1, 3)\n"
          ]
        }
      ],
      "source": [
        "# Access the results of the classical register of task #1\n",
        "result_1 = result[1][\"meas\"]\n",
        "print(f\"Result shape: {result_1.shape}\")\n",
        "\n",
        "# Access the bit-flip corrections\n",
        "flips_1 = result[1][\"measurement_flips.meas\"]\n",
        "print(f\"Bit-flip corrections shape: {flips_1.shape}\")\n",
        "\n",
        "# Undo the bit flips via classical XOR\n",
        "unflipped_result_1 = result_1 ^ flips_1"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bb0c9225-9a52-4d94-b75d-6ae408f4e029",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Passi successivi\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Suggerimenti\">\n",
        "  * Scopri [alcuni esempi](/docs/guides/executor-examples) che utilizzano Executor.\n",
        "  * Scopri il [modello](/docs/guides/directed-execution-model) di esecuzione diretta.\n",
        "  * Comprendere [la trasmissione tramite Executor](/docs/guides/executor-broadcasting).\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
}