{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "235dcb79",
   "metadata": {},
   "source": [
    "# How to use Monte Carlo integration with Fire Opal\n",
    "\n",
    "**Learn the basics of estimating an expectation value with `integrate_monte_carlo`**\n",
    "\n",
    "Fire Opal's [`integrate_monte_carlo`](https://docs.q-ctrl.com/references/fire-opal/fireopal/fireopal.integrate_monte_carlo) function provides an end-to-end workflow for Monte Carlo integration on quantum hardware. There are two ways to define the problem:\n",
    "\n",
    "1. Let Fire Opal construct the required circuits from a supported probability distribution and objective function.\n",
    "2. Provide a custom preparation circuit that already encodes the quantity to estimate.\n",
    "\n",
    "This guide uses one small example for each workflow. The goal is to focus on how to use the function rather than on a detailed financial model or a complex circuit construction.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6bf0b8ce",
   "metadata": {},
   "source": [
    "## Summary workflow\n",
    "\n",
    "The general workflow for using `integrate_monte_carlo` is:\n",
    "\n",
    "1. Import Fire Opal and configure your credentials.\n",
    "2. Choose a supported quantum backend.\n",
    "3. Define the Monte Carlo problem using either:\n",
    "   - a supported probability distribution and objective function, or\n",
    "   - a custom preparation circuit.\n",
    "4. Submit the problem with `integrate_monte_carlo`.\n",
    "5. Retrieve and inspect the estimated value.\n",
    "\n",
    "The first example uses a European call delta objective. The second uses a small custom circuit that represents four equally likely outcomes and marks one of them as a successful outcome.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9f740a83",
   "metadata": {},
   "source": [
    "## 1. Imports and initialization\n",
    "\n",
    "Import Fire Opal.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "0b51b005",
   "metadata": {},
   "outputs": [],
   "source": [
    "import fireopal as fo\n",
    "import qctrlvisualizer as qv\n",
    "import matplotlib.pyplot as plt\n",
    "from qiskit import QuantumCircuit, QuantumRegister\n",
    "from qiskit.qasm2 import dumps\n",
    "\n",
    "plt.style.use(qv.get_qctrl_style())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "551b37f3",
   "metadata": {},
   "source": [
    "If you experience an error while attempting to import the above libraries, please run the following command using the terminal. Please note that after installing new packages, you will need to restart your notebook session or kernel for the newly installed packages to be recognized."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "abbf9c12",
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install fire-opal matplotlib qiskit-ibm-runtime qctrl-visualizer qiskit qiskit_qasm3_import"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02af5340",
   "metadata": {},
   "source": [
    "Authenticate your Q-CTRL account and create the credentials for your hardware provider. This example uses IBM Quantum.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "248ac034",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Q-CTRL authentication successful!\n"
     ]
    }
   ],
   "source": [
    "# Authenticate your Q-CTRL account.\n",
    "api_key = \"YOUR_QCTRL_API_KEY\"\n",
    "fo.authenticate_qctrl_account(api_key=api_key)\n",
    "\n",
    "# Create IBM Quantum credentials.\n",
    "token = \"YOUR_IBM_CLOUD_API_KEY\"\n",
    "instance = \"YOUR_IBM_CRN\"\n",
    "\n",
    "credentials = fo.credentials.make_credentials_for_ibm_cloud(\n",
    "    token=token, instance=instance\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d1d1b596",
   "metadata": {},
   "source": [
    "## 2. Choose a backend\n",
    "\n",
    "Use [`show_supported_devices`](https://docs.q-ctrl.com/references/fire-opal/fireopal/fireopal.show_supported_devices) to list the backends available through the credentials you provided. Select one of the returned backend names for the integration.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f5a37290",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ibm_kingston\n",
      "ibm_boston\n",
      "ibm_marrakesh\n",
      "ibm_phoenix\n",
      "ibm_miami\n",
      "ibm_pittsburgh\n",
      "ibm_fez\n"
     ]
    }
   ],
   "source": [
    "supported_devices = fo.show_supported_devices(credentials=credentials)[\n",
    "    \"supported_devices\"\n",
    "]\n",
    "\n",
    "for device in supported_devices:\n",
    "    print(device)\n",
    "\n",
    "backend_name = \"your_desired_backend\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb245b4a",
   "metadata": {},
   "source": [
    "## 3. Example 1: European call delta using the high-level workflow\n",
    "\n",
    "Fire Opal constructs the required quantum circuits from a supported probability distribution and objective function. Currently it provides the following financial objective-function constructors:\n",
    "\n",
    "- `make_european_call_delta_objective`\n",
    "- `make_european_call_pricing_objective`\n",
    "- `make_fixed_income_pricing_objective`\n",
    "\n",
    "See the [Fire Opal Monte Carlo integration overview](https://docs.q-ctrl.com/fire-opal/execute/run-algorithms/fire-opal-monte-carlo-integration) for the supported distributions and objective functions.\n",
    "\n",
    "For this example, consider a uniformly distributed variable represented by eight discrete points between $0$ and $1$. You use a strike price of $0.5$ and the European call delta objective.\n",
    "\n",
    "The quantity of interest is\n",
    "\n",
    "$$\n",
    "\\mathbb{E}[f(X)],\n",
    "$$\n",
    "\n",
    "where\n",
    "\n",
    "$$\n",
    "f(X) =\n",
    "\\begin{cases}\n",
    "1, & X > 0.5, \\\\\n",
    "0, & X \\leq 0.5.\n",
    "\\end{cases}\n",
    "$$\n",
    "\n",
    "This small example demonstrates the high-level interface without reproducing the complete financial model from the [European options application guide](https://docs.q-ctrl.com/fire-opal/apply/price-european-options-using-monte-carlo-integration).\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "abd5e1d4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'objective_function_parameters': {'objective_function_name': 'european_call_delta',\n",
       "  'strike_price': 0.5,\n",
       "  'bounds': (0.0, 1.0)},\n",
       " 'distribution_parameters': {'distribution_name': 'uniform', 'uncertainty': 8}}"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "point_count = 8\n",
    "bounds = (0.0, 1.0)\n",
    "strike_price = 0.5\n",
    "\n",
    "distribution = fo.make_uniform_distribution(uncertainty=point_count)\n",
    "\n",
    "objective = fo.make_european_call_delta_objective(\n",
    "    strike_price=strike_price, bounds=bounds\n",
    ")\n",
    "\n",
    "problem = fo.make_monte_carlo_problem(\n",
    "    objective_function_parameters=objective, distribution_parameters=distribution\n",
    ")\n",
    "\n",
    "problem"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "640088d6",
   "metadata": {},
   "source": [
    "The eight discrete values have equal probability. Four are above the strike price and four are not, so the exact expectation value for this reference problem is\n",
    "\n",
    "$$\n",
    "\\mathbb{E}[f(X)] = \\frac{4}{8} = 0.5.\n",
    "$$\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a5286664",
   "metadata": {},
   "source": [
    "## 4. Run the Monte Carlo integration\n",
    "\n",
    "Pass the assembled problem and execution settings directly to `integrate_monte_carlo`. Fire Opal constructs the required state-preparation and amplitude-estimation circuits and executes them on the selected backend.\n",
    "\n",
    "For a starter example, let's limit the integration to 10 iterations.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "32db0d0a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "This function performs multiple consecutive runs. Wait time may vary depending on hardware queues.\n",
      "\n",
      "Job submitted.\n"
     ]
    }
   ],
   "source": [
    "job = fo.integrate_monte_carlo(\n",
    "    problem=problem,\n",
    "    credentials=credentials,\n",
    "    backend_name=backend_name,\n",
    "    integrator_options={\"max_iteration_count\": 10},\n",
    ")\n",
    "\n",
    "print(\"Job submitted.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6be13ea2",
   "metadata": {},
   "source": [
    "## 5. Retrieve the result\n",
    "\n",
    "`integrate_monte_carlo` returns a Fire Opal job. Call `result()` to retrieve the completed integration output.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "8a35a834",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Estimate: 0.487435\n",
      "Variance: 0.000070\n",
      "Standard deviation: 0.008392\n",
      "Iterations: 10\n"
     ]
    }
   ],
   "source": [
    "result = job.result()\n",
    "\n",
    "estimate = result[\"estimate\"]\n",
    "variance = result[\"variance\"]\n",
    "iteration_count = result[\"iteration_count\"]\n",
    "metadata = result[\"metadata\"]\n",
    "\n",
    "print(f\"Estimate: {estimate:.6f}\")\n",
    "print(f\"Variance: {variance:.6f}\")\n",
    "print(f\"Standard deviation: {variance**0.5:.6f}\")\n",
    "print(f\"Iterations: {iteration_count}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b9e79a42",
   "metadata": {},
   "source": [
    "## 6. Compare with the reference value\n",
    "\n",
    "In this example, the probability distribution contains eight discrete values, which can be encoded using only three qubits. Even with this small problem and a limited number of Monte Carlo iterations, the hardware estimate is already close to the target value. Increasing the number of iterations gives the integration procedure additional opportunities to refine the estimate and can improve its precision. The exact value for this simple problem is $0.5$. Comparing the hardware estimate with the reference value provides a quick check of the completed workflow.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "a86df2d9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Reference value: 0.500000\n",
      "Absolute difference: 0.012565\n"
     ]
    }
   ],
   "source": [
    "reference_value = 0.5\n",
    "absolute_difference = abs(estimate - reference_value)\n",
    "\n",
    "print(f\"Reference value: {reference_value:.6f}\")\n",
    "print(f\"Absolute difference: {absolute_difference:.6f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "997269a7",
   "metadata": {},
   "source": [
    "## 7. Example 2: submit a custom preparation circuit\n",
    "\n",
    "You can also use `integrate_monte_carlo` when you already have a quantum circuit that encodes the Monte Carlo problem. The preparation circuit must encode the probability to estimate in a single-qubit register named `target` or `output`. Consider four equally likely outcomes. You want to estimate the probability that one particular outcome occurs.\n",
    "\n",
    "Two data qubits represent the four possible outcomes:\n",
    "\n",
    "$$\n",
    "|00\\rangle,\\ |01\\rangle,\\ |10\\rangle,\\ |11\\rangle.\n",
    "$$\n",
    "\n",
    "Hadamard gates prepare them with equal probability. You then mark only $|11\\rangle$ by flipping the `output` qubit. The preparation circuit therefore encodes\n",
    "\n",
    "$$\n",
    "p = \\Pr(\\text{marked outcome}) = \\frac{1}{4}.\n",
    "$$\n",
    "\n",
    "This is a small Monte Carlo integration problem: the circuit loads a discrete distribution and evaluates a binary objective function, while keeping the circuit construction easy to follow.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "a55c6ada",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"word-wrap: normal;white-space: pre;background: #fff0;line-height: 1.1;font-family: &quot;Courier New&quot;,Courier,monospace\">        ┌───┐     \n",
       "data_0: ┤ H ├──■──\n",
       "        ├───┤  │  \n",
       "data_1: ┤ H ├──■──\n",
       "        └───┘┌─┴─┐\n",
       "output: ─────┤ X ├\n",
       "             └───┘</pre>"
      ],
      "text/plain": [
       "        ┌───┐     \n",
       "data_0: ┤ H ├──■──\n",
       "        ├───┤  │  \n",
       "data_1: ┤ H ├──■──\n",
       "        └───┘┌─┴─┐\n",
       "output: ─────┤ X ├\n",
       "             └───┘"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data = QuantumRegister(2, \"data\")\n",
    "output = QuantumRegister(1, \"output\")\n",
    "\n",
    "preparation_circuit = QuantumCircuit(data, output)\n",
    "\n",
    "# Load four equally likely outcomes.\n",
    "preparation_circuit.h(data[0])\n",
    "preparation_circuit.h(data[1])\n",
    "\n",
    "# Mark the |11> outcome.\n",
    "preparation_circuit.ccx(data[0], data[1], output[0])\n",
    "\n",
    "preparation_circuit.draw(\"text\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "79d1792f",
   "metadata": {},
   "source": [
    "Serialize the circuit as OpenQASM 2 and provide it through the `preparation_circuit` field. Fire Opal uses this circuit as the state-preparation operator and manages the amplitude-estimation workflow, hardware execution, error suppression, and classical post-processing.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "5c75bc17",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "This function performs multiple consecutive runs. Wait time may vary depending on hardware queues.\n",
      "\n",
      "Estimate: 0.245243\n",
      "Reference value: 0.250000\n",
      "Absolute difference: 0.004757\n"
     ]
    }
   ],
   "source": [
    "circuit_job = fo.integrate_monte_carlo(\n",
    "    problem={\"preparation_circuit\": dumps(preparation_circuit)},\n",
    "    credentials=credentials,\n",
    "    backend_name=backend_name,\n",
    "    integrator_options={\"max_iteration_count\": 10},\n",
    ")\n",
    "\n",
    "circuit_result = circuit_job.result()\n",
    "\n",
    "circuit_estimate = circuit_result[\"estimate\"]\n",
    "circuit_reference = 0.25\n",
    "\n",
    "print(f\"Estimate: {circuit_estimate:.6f}\")\n",
    "print(f\"Reference value: {circuit_reference:.6f}\")\n",
    "print(f\"Absolute difference: {abs(circuit_estimate - circuit_reference):.6f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "972fa75e",
   "metadata": {},
   "source": [
    "## Next steps\n",
    "\n",
    "The two examples use the same `integrate_monte_carlo` function but start from different levels of abstraction:\n",
    "\n",
    "- Use the **high-level workflow** when the problem can be described with one of Fire Opal's supported distributions and objective functions.\n",
    "- Use the **custom-circuit workflow** when you already have a circuit that performs distribution loading and objective-function encoding.\n",
    "\n",
    "The [Fire Opal Monte Carlo integration overview](https://docs.q-ctrl.com/fire-opal/execute/run-algorithms/fire-opal-monte-carlo-integration) lists the currently supported constructors and explains both workflows.\n",
    "\n",
    "For a complete finance application, continue with [Price European options using Monte Carlo integration](https://docs.q-ctrl.com/fire-opal/apply/price-european-options-using-monte-carlo-integration).\n",
    "\n",
    "For more detailed integrations, `integrator_options` can be used to configure settings such as `max_iteration_count`, `target_variance`, and `full_output`.\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "qiskit2",
   "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.12.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
