{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "7e51aef7-70db-4772-a53f-100af6ad6902",
      "metadata": {},
      "source": [
        "---\n",
        "title: Estimator examples\n",
        "description: Practical examples of using the Estimator primitive in Qiskit Runtime.\n",
        "---\n",
        "\n",
        "# Estimator examples\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "10cf3d45-503c-41c9-b0a1-51c23e32bc5f",
      "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",
        "<details>\n",
        "  <summary><b>Package versions</b></summary>\n",
        "\n",
        "  The code on this page was developed using the following requirements.\n",
        "  We recommend using these versions or newer.\n",
        "\n",
        "  ```\n",
        "  qiskit[all]~=2.3.0\n",
        "  qiskit-ibm-runtime~=0.43.1\n",
        "  ```\n",
        "</details>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3a98beb8-d1df-4daf-80ce-d51e4dc31cfa",
      "metadata": {},
      "source": [
        "The examples in this section illustrate some common ways to use Estimator. Before running these examples, follow the instructions in [Install Qiskit.](install-qiskit)\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  These examples all use the primitives from Qiskit Runtime, but you could use the base primitives instead.\n",
        "</Admonition>\n",
        "\n",
        "Efficiently calculate and interpret expectation values of the quantum operators required for many algorithms with Estimator. Explore uses in molecular modeling, machine learning, and complex optimization problems.\n",
        "\n",
        "## Run a single experiment\n",
        "\n",
        "Use Estimator to determine the expectation value of a single circuit-observable pair.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "6bc4a6a3-612e-4ad8-9fe3-3d56a4cb9a8f",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            " > Expectation value: 0.007735697018533441\n",
            " > Metadata: {'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}\n"
          ]
        }
      ],
      "source": [
        "import numpy as np\n",
        "from qiskit.circuit.library import iqp\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit.quantum_info import SparsePauliOp, random_hermitian\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2 as Estimator\n",
        "\n",
        "n_qubits = 50\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=n_qubits\n",
        ")\n",
        "\n",
        "mat = np.real(random_hermitian(n_qubits, seed=1234))\n",
        "circuit = iqp(mat)\n",
        "observable = SparsePauliOp(\"Z\" * 50)\n",
        "\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=1)\n",
        "isa_circuit = pm.run(circuit)\n",
        "isa_observable = observable.apply_layout(isa_circuit.layout)\n",
        "\n",
        "estimator = Estimator(mode=backend)\n",
        "job = estimator.run([(isa_circuit, isa_observable)])\n",
        "result = job.result()\n",
        "\n",
        "print(f\" > Expectation value: {result[0].data.evs}\")\n",
        "print(f\" > Metadata: {result[0].metadata}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c8594feb-0516-4cca-9064-232906b980a4",
      "metadata": {},
      "source": [
        "## Run multiple experiments in a single job\n",
        "\n",
        "Use Estimator to determine the expectation values of multiple circuit-observable pairs.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "662e73e9-8454-470a-b6aa-e84343005ca6",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            ">>> Expectation values for PUB 0: 0.0185546875\n",
            ">>> Standard errors for PUB 0: 0.015601139924387178\n",
            ">>> Expectation values for PUB 1: -0.09142077434760362\n",
            ">>> Standard errors for PUB 1: 0.03358006320017227\n",
            ">>> Expectation values for PUB 2: -0.001953125\n",
            ">>> Standard errors for PUB 2: 0.013875265857795725\n"
          ]
        }
      ],
      "source": [
        "import numpy as np\n",
        "from qiskit.circuit.library import iqp\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit.quantum_info import SparsePauliOp, random_hermitian\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2 as Estimator\n",
        "\n",
        "n_qubits = 50\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=n_qubits\n",
        ")\n",
        "\n",
        "rng = np.random.default_rng()\n",
        "mats = [np.real(random_hermitian(n_qubits, seed=rng)) for _ in range(3)]\n",
        "\n",
        "pubs = []\n",
        "circuits = [iqp(mat) for mat in mats]\n",
        "observables = [\n",
        "    SparsePauliOp(\"X\" * 50),\n",
        "    SparsePauliOp(\"Y\" * 50),\n",
        "    SparsePauliOp(\"Z\" * 50),\n",
        "]\n",
        "\n",
        "# Get ISA circuits\n",
        "pm = generate_preset_pass_manager(optimization_level=1, backend=backend)\n",
        "\n",
        "for qc, obs in zip(circuits, observables):\n",
        "    isa_circuit = pm.run(qc)\n",
        "    isa_obs = obs.apply_layout(isa_circuit.layout)\n",
        "    pubs.append((isa_circuit, isa_obs))\n",
        "\n",
        "estimator = Estimator(backend)\n",
        "job = estimator.run(pubs)\n",
        "job_result = job.result()\n",
        "\n",
        "for idx in range(len(pubs)):\n",
        "    pub_result = job_result[idx]\n",
        "    print(f\">>> Expectation values for PUB {idx}: {pub_result.data.evs}\")\n",
        "    print(f\">>> Standard errors for PUB {idx}: {pub_result.data.stds}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5176c806-e00d-4def-93b4-64216bf8cc64",
      "metadata": {},
      "source": [
        "## Run parameterized circuits\n",
        "\n",
        "Use Estimator to run three experiments in a single job, leveraging parameter values to increase circuit reusability.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "3f991c86-8bcd-4d9e-bed1-a6a7ac0cabb6",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            ">>> Expectation values: [[ 0.99448627  0.94805756  0.80317513  0.56626438  0.29038667 -0.02010529\n",
            "  -0.30613927 -0.5911369  -0.81581866 -0.94101035 -0.99303537 -0.94826483\n",
            "  -0.8098078  -0.59300234 -0.33287723 -0.01222899  0.29100849  0.57351886\n",
            "   0.80711328  0.95531205  0.99635171]\n",
            " [ 0.00808357  0.31152832  0.61663123  0.81208779  0.95178844  0.99199902\n",
            "   0.9370722   0.79281158  0.56688619  0.28748488 -0.01948347 -0.31857553\n",
            "  -0.57434795 -0.79737154 -0.95178844 -0.99842442 -0.95427569 -0.79882244\n",
            "  -0.58761329 -0.27546316  0.00538905]\n",
            " [-0.01906893 -0.32313549 -0.58450423 -0.8033824  -0.94930119 -0.99448627\n",
            "  -0.94121762 -0.80296786 -0.57186069 -0.29764116  0.02445798  0.31753918\n",
            "   0.6054386   0.81644048  0.94183943  0.98681724  0.93955945  0.80027334\n",
            "   0.57082434  0.29432482 -0.01513078]\n",
            " [ 0.99075539  0.93375586  0.78970252  0.56688619  0.29536118 -0.00870538\n",
            "  -0.31401557 -0.60688949 -0.81084416 -0.94743575 -0.99344991 -0.94722848\n",
            "  -0.80110242 -0.57103161 -0.30075022 -0.00103636  0.30551746  0.58533331\n",
            "   0.80669874  0.94142489  0.99407173]]\n",
            ">>> Standard errors: [[0.00359184 0.00438386 0.00852894 0.01096216 0.00952795 0.01084166\n",
            "  0.01092139 0.01112474 0.00835954 0.00493214 0.00305847 0.00505781\n",
            "  0.0081545  0.00942587 0.01243794 0.01279255 0.01449143 0.01001158\n",
            "  0.00686416 0.00608612 0.00306803]\n",
            " [0.01380567 0.01025795 0.00809922 0.00742183 0.0050425  0.00375401\n",
            "  0.00555313 0.0079511  0.01037733 0.01328277 0.01431205 0.01218068\n",
            "  0.01144855 0.00865455 0.00559959 0.00383215 0.0044145  0.00880595\n",
            "  0.01191713 0.01291607 0.01212646]\n",
            " [0.01005963 0.00753399 0.00858187 0.00673876 0.00409901 0.0026568\n",
            "  0.00439918 0.00771471 0.00939481 0.00991522 0.01046032 0.01036158\n",
            "  0.00773218 0.00618488 0.00375851 0.00374272 0.0040234  0.00837196\n",
            "  0.01109589 0.01055713 0.00823229]\n",
            " [0.00376252 0.00513786 0.00521975 0.01071544 0.00701596 0.01081168\n",
            "  0.01136338 0.01045901 0.00709637 0.00554858 0.00372386 0.00470944\n",
            "  0.0063878  0.00980035 0.01048143 0.00968916 0.01234788 0.00880073\n",
            "  0.00779767 0.00458181 0.00341765]]\n",
            ">>> Metadata: {'shots': 10016, 'target_precision': 0.01, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}\n"
          ]
        }
      ],
      "source": [
        "import numpy as np\n",
        "\n",
        "from qiskit.circuit import QuantumCircuit, Parameter\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2 as Estimator\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(operational=True, simulator=False)\n",
        "\n",
        "# Step 1: Map classical inputs to a quantum problem\n",
        "theta = Parameter(\"θ\")\n",
        "\n",
        "chsh_circuit = QuantumCircuit(2)\n",
        "chsh_circuit.h(0)\n",
        "chsh_circuit.cx(0, 1)\n",
        "chsh_circuit.ry(theta, 0)\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",
        "ZZ = SparsePauliOp.from_list([(\"ZZ\", 1)])\n",
        "ZX = SparsePauliOp.from_list([(\"ZX\", 1)])\n",
        "XZ = SparsePauliOp.from_list([(\"XZ\", 1)])\n",
        "XX = SparsePauliOp.from_list([(\"XX\", 1)])\n",
        "ops = [ZZ, ZX, XZ, XX]\n",
        "\n",
        "# Step 2: Optimize problem for quantum execution.\n",
        "\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=1)\n",
        "chsh_isa_circuit = pm.run(chsh_circuit)\n",
        "isa_observables = [\n",
        "    operator.apply_layout(chsh_isa_circuit.layout) for operator in ops\n",
        "]\n",
        "\n",
        "# Step 3: Execute using Qiskit primitives.\n",
        "\n",
        "# Reshape observable array for broadcasting\n",
        "reshaped_ops = np.fromiter(isa_observables, dtype=object)\n",
        "reshaped_ops = reshaped_ops.reshape((4, 1))\n",
        "\n",
        "estimator = Estimator(backend, options={\"default_shots\": int(1e4)})\n",
        "job = estimator.run([(chsh_isa_circuit, reshaped_ops, individual_phases)])\n",
        "# Get results for the first (and only) PUB\n",
        "pub_result = job.result()[0]\n",
        "print(f\">>> Expectation values: {pub_result.data.evs}\")\n",
        "print(f\">>> Standard errors: {pub_result.data.stds}\")\n",
        "print(f\">>> Metadata: {pub_result.metadata}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "117454c0-c8df-48cd-8503-f4fd137d6991",
      "metadata": {},
      "source": [
        "## Use batches and advanced options\n",
        "\n",
        "Explore the batch [execution mode](/docs/guides/execution-modes) and advanced options to optimize circuit performance on QPUs.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "f009e993-98fe-451c-96f5-738153005543",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            " > Expectation value: -0.04995359041431103\n",
            " > Metadata: {'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}\n",
            " > Another Expectation value: 0.0\n",
            " > More Metadata: {'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}\n"
          ]
        }
      ],
      "source": [
        "import numpy as np\n",
        "from qiskit.circuit.library import iqp\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit.quantum_info import SparsePauliOp, random_hermitian\n",
        "from qiskit_ibm_runtime import (\n",
        "    QiskitRuntimeService,\n",
        "    Batch,\n",
        "    EstimatorV2 as Estimator,\n",
        ")\n",
        "\n",
        "n_qubits = 15\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=n_qubits\n",
        ")\n",
        "\n",
        "rng = np.random.default_rng(1234)\n",
        "mat = np.real(random_hermitian(n_qubits, seed=rng))\n",
        "circuit = iqp(mat)\n",
        "mat = np.real(random_hermitian(n_qubits, seed=rng))\n",
        "another_circuit = iqp(mat)\n",
        "observable = SparsePauliOp(\"X\" * n_qubits)\n",
        "another_observable = SparsePauliOp(\"Y\" * n_qubits)\n",
        "\n",
        "pm = generate_preset_pass_manager(optimization_level=1, backend=backend)\n",
        "isa_circuit = pm.run(circuit)\n",
        "another_isa_circuit = pm.run(another_circuit)\n",
        "isa_observable = observable.apply_layout(isa_circuit.layout)\n",
        "another_isa_observable = another_observable.apply_layout(\n",
        "    another_isa_circuit.layout\n",
        ")\n",
        "\n",
        "# The context manager automatically closes the batch.\n",
        "with Batch(backend=backend) as batch:\n",
        "    estimator = Estimator(mode=batch)\n",
        "\n",
        "    estimator.options.resilience_level = 1\n",
        "\n",
        "    job = estimator.run([(isa_circuit, isa_observable)])\n",
        "    another_job = estimator.run(\n",
        "        [(another_isa_circuit, another_isa_observable)]\n",
        "    )\n",
        "    result = job.result()\n",
        "    another_result = another_job.result()\n",
        "\n",
        "    # first job\n",
        "    print(f\" > Expectation value: {result[0].data.evs}\")\n",
        "    print(f\" > Metadata: {result[0].metadata}\")\n",
        "\n",
        "    # second job\n",
        "    print(f\" > Another Expectation value: {another_result[0].data.evs}\")\n",
        "    print(f\" > More Metadata: {another_result[0].metadata}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e207719d-da1b-4af2-ae63-4cb033865a1b",
      "metadata": {},
      "source": [
        "## Next steps\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recommendations\">\n",
        "  * [Specify advanced runtime options](runtime-options-overview).\n",
        "  * Practice with primitives by working through the [Cost function lesson](/learning/courses/variational-algorithm-design/cost-functions) in IBM Quantum® Learning.\n",
        "  * Learn how to transpile locally in the [Transpile](/docs/guides/transpile/) section.\n",
        "  * Try the [Compare transpiler settings](/docs/guides/circuit-transpilation-settings) guide.\n",
        "  * Read [Migrate to V2 primitives](/docs/guides/v2-primitives).\n",
        "  * Understand the [Job limits](/docs/guides/job-limits) when sending a job to an IBM® QPU.\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
}