diff --git a/.pylintdict b/.pylintdict index 357add023..51c6a9431 100644 --- a/.pylintdict +++ b/.pylintdict @@ -1,3 +1,4 @@ +acyclic adam adjoint aer @@ -18,13 +19,17 @@ autosummary backend backends backpropagation +bayes +bayesian benchmarking bergholm bitstring bitstrings bivariate +bloch bool boolean +borujeni cargs carlo cbit @@ -83,6 +88,7 @@ farrokh fidelities fidelityquantumkernel formatter +frac frontend func gambetta @@ -90,8 +96,11 @@ gaussian gellmann getter gpu +grover +guang guzik hamiltonian +hao hashable havlíček hilbert @@ -106,6 +115,8 @@ inlier inplace instantiation instantiations +interdependencies +isaac isometry iten iterable @@ -124,6 +135,7 @@ langle lukin macos makefile +mary matmul matplotlib maxiter @@ -141,6 +153,7 @@ multioutput mxd mypy nat +nbsphinx ndarray nielsen nn @@ -191,6 +204,9 @@ qae qarg qargs qasm +qb +qbayesian +qbi qc qgan qgans @@ -205,6 +221,7 @@ qubits rangle rbf readme +recalibration regressor regressors regs @@ -226,6 +243,7 @@ shalev shende shwartz sigmoid +sima sklearn softmax sparsearray @@ -235,6 +253,7 @@ stdlib stdlib stdout str +subclasses subcircuits submodules subobjects @@ -248,6 +267,7 @@ temme tensored terra th +theodore toctree todo traceback @@ -280,6 +300,7 @@ vz wikipedia williams wrt +yoder zoufal zsh θ diff --git a/docs/images/Burglary_Alarm.png b/docs/images/Burglary_Alarm.png new file mode 100644 index 000000000..e683632da Binary files /dev/null and b/docs/images/Burglary_Alarm.png differ diff --git a/docs/images/Two_Node_Bayesian_Network.png b/docs/images/Two_Node_Bayesian_Network.png new file mode 100644 index 000000000..28bf269b3 Binary files /dev/null and b/docs/images/Two_Node_Bayesian_Network.png differ diff --git a/docs/tutorials/13_quantum_bayesian_inference.ipynb b/docs/tutorials/13_quantum_bayesian_inference.ipynb new file mode 100644 index 000000000..9aee06e8a --- /dev/null +++ b/docs/tutorials/13_quantum_bayesian_inference.ipynb @@ -0,0 +1,747 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4f1ee7dfd66dd6ac", + "metadata": { + "collapsed": false + }, + "source": [ + "# Quantum Bayesian Inference\n", + "\n", + "## Overview\n", + "This notebook demonstrates a quantum Bayesian inference (QBI) implementations provided in `qiskit-machine-learning`, and how it can be integrated into basic quantum machine learning (QML) workflows.\n", + "\n", + "The tutorial is structured as follows:\n", + "\n", + "1. [Introduction](#1.-introduction)\n", + "2. [How to Instantiate QBI](#2.-how-to-instantiate-qbi)\n", + "3. [How to Run Rejection Sampling](#3.-how-to-run-rejection-sampling)\n", + "4. [How to Run an Inference](#4.-how-to-run-an-inference)" + ] + }, + { + "cell_type": "markdown", + "id": "494f210f33019c5b", + "metadata": { + "collapsed": false + }, + "source": [ + "## 1. Introduction" + ] + }, + { + "cell_type": "markdown", + "source": [ + "### 1.1. Quantum vs. Classical Bayesian Inference\n", + "\n", + "Bayesian networks, or belief networks, are graphical models that illustrate probabilistic relationships between variables using nodes (representing variables) and edges (indicating conditional dependencies) in a directed acyclic graph. Each node is associated with conditional probability tables (CPTs) that detail the influence of parent nodes on their children. \n", + "\n", + "In these networks, Bayesian inference is key for updating probabilities. It employs Bayes' theorem to revise the likelihood of hypotheses based on new data, considering the network's variable interdependencies. For instance, in a network assessing diseases based on symptoms, observing new symptoms allows for recalculating disease probabilities. This recalibration combines the disease's prior probability with the observed symptom likelihood, leading to an updated, more precise disease probability. Thus, Bayesian inference is a dynamic process of adjusting our understanding of one variable in light of new information about others, facilitating informed, evidence-based decisions.\n", + "\n", + "Exact inference on Bayesian networks is \\#P-hard. That is why usually approximate inference is used to sample from the distribution on query variables given evidence variables. QBI efficiently utilizes the structure of Bayesian networks represented by a quantum circuit that represent the probability distributions. By employing a quantum version of rejection sampling and leveraging amplitude amplification, quantum computation achieves a significant speedup, making it possible to obtain samples much faster. \n", + "\n", + "This tutorial will guide you through the process of using the QBayesian class to perform such inference tasks. This inference algorithm implements the algorithm from the paper \"Quantum inference on Bayesian networks\" by Low, Guang Hao et al. This leads to a speedup per sample from $O(nmP(e)^{-1})$ to $O(n2^{m}P(e)^{-\\frac{1}{2}})$, where n is the number of nodes in the Bayesian network with at most m parents per node and e the evidence.\n", + "\n", + "### 1.2. Implementation in `qiskit-machine-learning`\n", + "\n", + "The QBI in `qiskit-machine-learning` can be used for different quantum circuits representing Bayesian networks with. The implementation is based on the `Sampler` primitive from [qiskit primitives](https://qiskit.org/documentation/apidoc/primitives.html). The primitive is the entry point to run QBI on either a simulator or real quantum hardware. QBI takes in an optional instance of its corresponding primitive, which can be any subclass of `BaseSampler`.\n", + "\n", + "The `qiskit.primitives` module provides a reference implementation for the `Sampler` class to run statevector simulations. By default, if no instance is passed to a QBI class, an instance of the corresponding reference primitive of `Sampler` is created automatically by QBI.\n", + "For more information about primitives please refer to the [primitives documentation](https://qiskit.org/documentation/apidoc/primitives.html).\n", + "\n", + "The `QBayesian` class is used for QBI in `qiskit-machine-learning`. It is initialized with a quantum circuit that represents a Bayesian network. This enables the execution of quantum rejection sampling and inference.\n" + ], + "metadata": { + "collapsed": false + }, + "id": "f65b0713535b3fd6" + }, + { + "cell_type": "markdown", + "id": "36c0c73ab1fe5686", + "metadata": { + "collapsed": false + }, + "source": [ + "## 2. How to Instantiate QBI" + ] + }, + { + "cell_type": "markdown", + "source": [ + "### 2.1. Create Rotations for the Bayesian Networks\n", + "In quantum computing, the rotation matrix around the y-axis, denoted as $R_y(\\theta)$, is used to rotate the state of a qubit around the y-axis of the Bloch sphere by an angle $\\theta$. This approach allows for precise control over the quantum state of a qubit, enabling the encoding of specific probabilities in quantum algorithms. When this rotation is applied to a qubit initially in the $|0\\rangle$ state, the resulting state $|\\psi\\rangle$ is:\n", + "$$ |\\psi\\rangle = R_y(\\theta)|0\\rangle = \\begin{pmatrix} \\cos\\left(\\frac{\\theta}{2}\\right) \\\\ \\sin\\left(\\frac{\\theta}{2}\\right) \\end{pmatrix} $$\n", + "\n", + "where\n", + "\n", + "* $R_y(\\theta) = \\begin{pmatrix} \\cos\\left(\\frac{\\theta}{2}\\right) & -\\sin\\left(\\frac{\\theta}{2}\\right) \\\\ \\sin\\left(\\frac{\\theta}{2}\\right) & \\cos\\left(\\frac{\\theta}{2}\\right) \\end{pmatrix}$\n", + "\n", + "\n", + "This state is a superposition of $|0\\rangle$ and $|1\\rangle$ with respective amplitudes $\\cos\\left(\\frac{\\theta}{2}\\right) $ and $\\sin\\left(\\frac{\\theta}{2}\\right) $. To set a specific probability $p$ for measuring the qubit in the $|1\\rangle$ state, you can determine $\\theta$ using $\\arcsin$:\n", + "$$ (\\sin^2\\left(\\frac{\\theta}{2}\\right) = p) \\Leftrightarrow (\\theta = 2\\arcsin\\left(\\sqrt{p}\\right)) $$\n", + "\n", + "The counter probability $q = 1 - p$, which is the probability of measuring the qubit in the $|0\\rangle$ state, is given by:\n", + "$$ q = \\cos^2\\left(\\frac{\\theta}{2}\\right) $$\n", + "\n", + "This approach can be extended for conditional probabilities. For example, with the Bayesian network shown above, you can use the following formula to calculate the joint probability distribution:\n", + "$$(X\\otimes{I})(I\\otimes{I}+P_1\\otimes{(R_y-I)})(X\\otimes{I})(I\\otimes{I}+P_1\\otimes{(R_y-I)})(R_y\\otimes{I})|00\\rangle$$" + ], + "metadata": { + "collapsed": false + }, + "id": "6adf88f1d249b336" + }, + { + "cell_type": "markdown", + "id": "f0be387a44da5bac", + "metadata": { + "collapsed": false + }, + "source": [ + "#### 2.1.1. Two Node Bayesian Network Example\n", + "\n", + "In the first example we consider a simple Bayesian network that is only based on two nodes." + ] + }, + { + "cell_type": "markdown", + "source": [ + "![Two Node Bayesian Network Example](../images/Two_Node_Bayesian_Network.png)" + ], + "metadata": { + "collapsed": false + }, + "id": "5a1d3cd4b14d9c1e" + }, + { + "cell_type": "markdown", + "id": "19b5a6da03a35a85", + "metadata": { + "collapsed": false + }, + "source": [ + "For the quantum circuit we need rotation angles that represent the conditional probability tables. The corresponding rotation angles are:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "326c1d2e72f41202", + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-03-15T12:25:43.964092Z", + "start_time": "2024-03-15T12:25:43.916109Z" + } + }, + "outputs": [], + "source": [ + "# Include libraries\n", + "import numpy as np\n", + "\n", + "# Define rotation angles\n", + "theta_X = 2 * np.arcsin(np.sqrt(0.2))\n", + "theta_Y_X = 2 * np.arcsin(np.sqrt(0.9))\n", + "theta_Y_nX = 2 * np.arcsin(np.sqrt(0.3))" + ] + }, + { + "cell_type": "markdown", + "id": "e1dd146c9d2bdad3", + "metadata": { + "collapsed": false + }, + "source": [ + "#### 2.1.2. Burglary Alarm Example\n", + "\n", + "Now consider a more complex network. Imagine you have an alarm system in your house that is triggered by either a burglary or an earthquake. You also have two neighbors, John and Mary, who will call you if they hear the alarm. The network has directed edges from the Burglary and Earthquake nodes to the Alarm node, indicating that both burglary and earthquake can cause the alarm to ring. There are also edges from the Alarm node to the John Calls and Mary Calls nodes, indicating that the alarm influences whether John and Mary call you." + ] + }, + { + "cell_type": "markdown", + "id": "69003c40f9bcbafd", + "metadata": { + "collapsed": false + }, + "source": [ + "![Burglary Alarm](../images/Burglary_Alarm.png)" + ] + }, + { + "cell_type": "markdown", + "id": "587dc2c38a0a3ca9", + "metadata": { + "collapsed": false + }, + "source": [ + "The Bayesian Network for this scenario involves the following variables:\n", + "\n", + "Burglary (B): Whether a burglary has occurred.\n", + "Earthquake (E): Whether an earthquake has occurred.\n", + "Alarm (A): Whether the alarm goes off.\n", + "John Calls (J): Whether John calls you.\n", + "Mary Calls (M): Whether Mary calls you.\n", + "\n", + "Use the conditional probability tables:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "a815411b4f10c78c", + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-03-15T12:25:43.977309Z", + "start_time": "2024-03-15T12:25:43.922941Z" + } + }, + "outputs": [], + "source": [ + "theta_B = 2 * np.arcsin(np.sqrt(0.001))\n", + "theta_E = 2 * np.arcsin(np.sqrt(0.002))\n", + "theta_A_nBnE = 2 * np.arcsin(np.sqrt(0.001))\n", + "theta_A_nBE = 2 * np.arcsin(np.sqrt(0.29))\n", + "theta_A_BnE = 2 * np.arcsin(np.sqrt(0.94))\n", + "theta_A_BE = 2 * np.arcsin(np.sqrt(0.95))\n", + "theta_J_nA = 2 * np.arcsin(np.sqrt(0.05))\n", + "theta_J_A = 2 * np.arcsin(np.sqrt(0.9))\n", + "theta_M_nA = 2 * np.arcsin(np.sqrt(0.9))\n", + "theta_M_A = 2 * np.arcsin(np.sqrt(0.3))" + ] + }, + { + "cell_type": "markdown", + "id": "473ea24e63019832", + "metadata": { + "collapsed": false + }, + "source": [ + "### 2.2. Create a Quantum Circuit for the Bayesian Networks\n", + "A Bayesian network can be represented as a quantum circuit where each node is a qubit, and the edges are quantum gates that represent the conditional dependencies." + ] + }, + { + "cell_type": "markdown", + "id": "33797564f68ae67", + "metadata": { + "collapsed": false + }, + "source": [ + "#### 2.2.1 Two Node Bayesian Network Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f99dbe56bc6910a", + "metadata": { + "collapsed": false, + "is_executing": true, + "ExecuteTime": { + "start_time": "2024-03-15T12:25:43.936275Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": "
", + "image/png": "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06ZNKCgowJEjRxAcHNzt/oCAAAwfPhzAjcM62dnZXb7SgAaWUaNGYc6cOYiOjoamaVi8eDFOnTpldizqAZYSKW/Lli3Yv38/jh49imHDht10nW+++Qbt7e0AgNbWVhQUFBhy7UPyDgsWLEBRUREaGxsBAIcPH0Z8fLzJqagnWEqktMuXL+Oll17Cf//7X8yZMwcJCQm4//77AQBr167Fjh07AAB///vfMXXqVMTHx8Nms8FqtXY7I4u8x4oVKxATE4PLly/j0Ucfxbhx4wAAy5YtwyeffALgxhl2MTExmD9/Ps6fP4+YmBi8+uqrAG7sKb322muYOXMmpkyZgmPHjrnnCqlNk9t9YQmRDr57hejm5mZlr7zsLTm9kbdsW2/J6cu4p0RERMpgKRERkTJ4RQfyKLvdbnaEW1I5my9ReTurnG2gYCmRR0VGRpodgUzGOUC3w8N3RESkDJ59R4YTETgcDrNj9EpwcLD7envUf5wD1FMsJSIiUgYP3xERkTJYSkREpAyWEhERKYOlREREymApERGRMlhKRESkDJYSEREpg6VERETKYCkREZEyWEpERKQMlhIRESmDpURERMpgKRERkTJYSkREpAyWEhERKYOlREREymApERGRMlhKRESkDJYSEREpg6VERETKYCkREZEyWEpERKQMlhIRESmDpURERMpgKRERkTL+D+kL6o/0beeWAAAAAElFTkSuQmCC" + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qiskit import QuantumRegister\n", + "from qiskit import QuantumCircuit\n", + "\n", + "# Define quantum registers\n", + "qrX = QuantumRegister(1, name=\"X\")\n", + "qrY = QuantumRegister(1, name=\"Y\")\n", + "# Define a 2-qubit quantum circuit\n", + "qc_2n = QuantumCircuit(qrX, qrY, name=\"Bayes net small\")\n", + "# Apply the R_Y_theta rotation gate on the first qubit\n", + "qc_2n.ry(theta_X, 0)\n", + "# Apply the controlled-R_Y_theta rotation gate\n", + "qc_2n.cry(theta_Y_X, control_qubit=qrX, target_qubit=qrY)\n", + "# Apply the X gate on the first qubit\n", + "qc_2n.x(0)\n", + "# Apply the controlled-R_Y_theta rotation gate\n", + "qc_2n.cry(theta_Y_nX, control_qubit=qrX, target_qubit=qrY)\n", + "# Apply another X gate on the first qubit\n", + "qc_2n.x(0)\n", + "qc_2n.draw(\"mpl\", style=\"bw\", plot_barriers=False, justify=\"none\", fold=-1)" + ] + }, + { + "cell_type": "markdown", + "id": "7596c28a61daad7d", + "metadata": { + "collapsed": false + }, + "source": [ + "#### 2.2.2. Burglary Alarm Example" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "79045cc1a7706f87", + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-03-15T12:25:44.289098Z", + "start_time": "2024-03-15T12:25:43.993735Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": "
", + "image/png": "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LWphSsA7Ll68qL59+7o1z7///W+lpaX5KBH8bevWrRo/frzL058/f14DBw70YSJYKSEhQf3799e8efM0YcIEZWZmqlu3bjLGaOrUqdnG/2Bx+vRpDR482K15XnzxRWVmZvooEfzthx9+0OzZs12e/vTp03r11Vd9mAhWCsV+ENLAgQN17tw5l6f/4IMPtHnzZh8mgj+lp6e7fXz70ksv6cKFCz5KBKsxFiDUJCcn64033nB5+qysLPXt21fGGB+mgj99++23WrRokcvTHz161K19JtAwDgAAELyCuphj3bp1kqTVq1fL4XA4/woXLqybbrpJCxYs0Ouvv64VK1aodOnSFqf1XOXKldW5c2ctXLhQS5cudT4+cuRI7dixQ23atNE999xjYULAe/73v//p0KFDbs2TkpKijz/+2EeJ4G/jxo1ze57Fixdr69atPkgDO0hKSlK9evX0wgsv6B//+IdWrlypoUOHqlq1alZH84lp06YpPT3drXn27t2rOXPm+CgR/G3MmDFuz/P555/ryJEjPkgDOwi1fjDUbdu2TQsWLHB7vrFjx/ogDazwySef6NSpU27Nc+TIEc2aNcs3gWALjAUIJZMmTdLFixfdmufXX3/Vjz/+6KNE8DdPzommT5+u06dP+yCNPTAOAAAQnIK6mOPylTmqVaumW265xflXs2ZN5c+fXydPntS0adN04MABa4N6wcCBAxUWFpbt6hxRUVGqWLGi6tSpY2EywLtmzJjh1/lgP55uy08++cTLSWAXefPm1dSpU3Xu3DmNHTtWzZo107PPPmt1LJ+hHwxt586d05dffun2fBcvXuRLvCAWav1gqPvss888mo9xIHh4elzLPhDcGAsQSugHQ9uJEyf0/fffuz1fWlqavvnmGx8ksgfGAQAAglMeqwP4SlZWljZt2iRJmjx5sm6++eZsz584cULdunXTt99+q4ceekhbtmxRWJj7tS2NGjVScnKyW7k80aJFixwvBVijRg2fXT69SpUqHr03gC8cPXrUo/mWLl2q+Ph4L6eBvxljPN4HRo4cqUmTJnk5ETzh6ViYk5iYGEVEROjixYtq27at18ctO42F7hx3/NmsWbPoB4NAZmamMjIyPJq3b9++eu2117ycCJ6gH0RuuHtFhstOnjypMmXKyOFweDcQ/O7w4cMezTd37lyOBWzCF+OA5NuxgHEA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jRs3dnn6QoUK6aWXXvJhIlglVPtBAEDoCMoj2P379zt/tf/666+rWbNm1/wbN26cxWkBuCsxMdHlDy/79Onj9gedsL/Jkyfrrrvuuu504eHhmjx5slq1auWHVID/DBkyRE888YRL077yyisuT4vAEBYWplmzZrn04WWBAgX0xRdfuH1FIyAQbN26VUlJSWrSpImef/75K56vVauWXn75Zf34448aNWqUBQl9p2XLlpo6dapLBR2tWrXStGnT/JAK/tSvXz8988wzXp8WCCShPA5IrP9bb73l8g893nnnHbev4gB7y5cvn77++muXfshZsGBB/e9//1P16tX9kAz+FOr9IAAgNATlbVa++eYb3XvvvS5N+9FHH+lvf/ubjxPhzwLl0mSBkjOUffLJJ3rzzTedV+L5sxo1auj5559Xjx495HA4/B8OPnfx4kUNHz5cY8aM0cGDB694vlWrVkpKSlLz5s0tSAf4njFGEyZM0Ntvv63ff//9iucbNmyol156SR06dLAgHfwhPT1dr776qt5//30dP34823MOh0Pt2rXT4MGD1bBhQ4sSAlcXKMfZgZDzxx9/1KuvvqoFCxZc8VypUqX01FNPqV+/fsqXL58F6eBrxhhNnTpVI0eO1JYtW654vm7duurbt68eeeQRC9IBOQuEPlay/21WfM3uObOysjRq1Cj997//1R9//HHF8zfffLMGDBigdu3aWZAO/pCSkqKXX35ZkydP1qlTp7I9Fx4ervvvv19DhgxR7dq1rQmIa7J7/3JZoOQEAASvoCzmgL0FygFQoOQMdcYYrVixQosWLdIbb7yh1NRUFStWTEeOHKGII0RcvHhR33zzjR577DGdOXNGhQoV0i+//MIvLhAyjDFauHChHnzwQWcbmD9/vluXnEVgO3funL788kv17t3buQ9s2LBBFSpUsDoacFWBcpwdKDkladu2bfrf//6nV199VampqYqNjVVycjK32AoRxhgtXbpU7dq105kzZ1SwYEHNnTtXTZs25ZwIthUofSzFHIGRMysrS99//706derkPB5esmQJV6cLIenp6Zo5c6aefvppnTlzRjExMdq8ebPi4+OtjoZrCJT+JVByAgCCV1DeZgWBZ/v27WratKmqVq2qG2+88aq/KpKkSZMmqUqVKqpUqZJ69uypixcvSrp00vbcc8+pZs2aqlu3rlq2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2Y5r1aql3r176/z585KkRYsWqXHjxqpZs6Zq1aqlvn37Kisry49rAE8kJSX57Woxd911l/7+97/7ZVlwjcPh0AcffOC3K7QkJSXZ7uTWlWOjJUuWqECBAtmOZc6ePet8ftOmTWrRooVq1KihGjVqaNasWZKkrKwsvfDCC6pdu7aqV6+uv//977pw4YLf1g1wxW233aann37aL8sqWrSoxowZ45dlwXUvvvii377EuuWWW/SPf/zDL8vKSW7Pi3M6Jt69e7datGihmJgY1a9f/4rXvNaYAcA6r7/+um644Qa/LOvBBx9Ux44d/bIsuCZPnjyaPHmy376Aev3111W5cmW/LAsAAMAdFHMANtC7d2/16tVLv//+u/r166fu3btfMc2uXbuUlJSkpUuXaseOHTp8+LAmTJiQbZp33nnnmvfImzVr1hUnQHXq1NH69eudf+3atbPF7UbCwsI0adIkt6+WkZycrP379ys5Odml6fPly6cpU6bYsjLR1Q8yXZ1u8uTJcjgc+uqrr6773PHjx7N9MVa1alXlyZNHJ06c8NbqXVfx4sU1duxYt+Zxd/tL0g033KDhw4e7G8+vOnTooJ9++knly5e/5jT16tXTqlWrtH79em3atElHjhxxfilTpEgRffLJJ/r111+1Zs0aLVu2TNOmTfNXfHgoIiJCU6ZMcevSwp60gZiYGL3//vsB9ws0V4qcpEuFKnXr1lX9+vV16623at26dc7nzp07pwceeEBVq1ZVvXr1dOedd2rHjh1+SO+aSpUqud0/ebIPNGzY0JZFja4cG0mXbkfx52OZAgUKSJLS09N1//3367XXXtPWrVu1efNm3XrrrZIufQm4du1arV27Vlu3blVYWJjeffddf60a4LI33njD7S8VPOkHRo8eHRC3WXL1uLdChQqqVq2a81j2008/zfb8+fPn9fTTT6tKlSqqU6dOtntsf/fdd2rUqJHq1q2rJk2aaMOGDT5dp5zkyZNHU6ZMcetqGZ5s/8jISE2ePNkWV+jK7XlxTsfEhQoV0muvvaaPP/74itfMacwAYJ3o6GhNnjzZrV9Ue9IPFitWTGPGjLHlOZG3PhvK6bwop3OrnMZMf6hTp46GDBni1jye7AO33XabnnnmGXfjAQAA+IcB4FepqalGkpFkUlNTzeHDh03BggXNxYsXjTHGZGVlmZIlS5rt27dnm2/48OGmd+/ezn9/++235pZbbnH+e/PmzebWW281O3bsMDExMdnmTU5ONg0bNjQpKSlGkjl58uQVuc6ePWsKFy5s1q1bd9WcVli4cKGJiIhw5vDmX3h4uPnyyy99vg6evo8tW7Y0kydPNsYY8/nnn5tGjRp5PN2uXbvMzTffbJo0aXLFOuf03GUjRoww7dq1y9X6eOqNN97wyfaXZEqUKGG2bdvm83W4Gk/ex/LlyzvbZ07Onj1rWrdubd55552rPt+nTx8zePBgn+WEd3366afG4XD4pA0UKFDA/Pjjj5asV273rR9++MHs27fvuu3iz+PdrFmzTN26dZ3/Pnv2rPn2229NVlaWMcaYUaNGmebNm3s1Z25lZWWZf/7znz7rBytWrGgOHjzo9/UyJuf31tVjo8WLF5t69epd9fXff/9906VLl6s+16dPHzN06FDnv7/44gtTp04dt3MC/rB9+3YTFxfns37g1Vdf9fs6+fr4+Hpjw7PPPmuefvppZ/9/6NAhY4wxJ06cMLGxsWbz5s3GGGN+/PFHU6tWLcv7ga+//trkyZPHJ9s/X758Zt68eX5fJ2N8d1582bWOia82duQ0Zli9/QEYM2nSJJ+NgwULFjSrVq3y+TpY/dlQTudFOZ1bXWvM9GffmJWVZf7+97/7bB+oWbOmOXbsmE/XAfCnMmXKGEmmTJkyVkexTKC8B4FynBkoOS8LlO3vS4HyHgTKvmWHnFyZA7DYvn37VKpUKeevrx0Oh8qVK6e9e/dmm27v3r3ZfplfoUIF5zQXL15Uz549NX78+Kv+oqpnz54aPny4ChYseM0cs2bNUsWKFa96yVmr3H777frmm28UFRXl1dfNly+fZs6cqQceeMCrr+stR44c0erVq52/eHjooYe0b9++K34x7sp0WVlZeuKJJzRq1KgrftWX03N/NmnSJMtuwdCvXz+9+eabXn/d+Ph4LVmyRFWrVvX6a1tl9+7dqlevnooVK6aYmBglJiZeMU1ycrJmzpypdu3aWZAQnujYsaNmzJjh9SsIFSxYUHPnzg3YX53edtttio+Pv+50f77t2OnTp7P92i5//vxq27at87EmTZpo9+7d3o6aKw6HQ++8846ee+45r7929erV9cMPPzjvo2knrh4bSdLOnTuVkJCgG2+8MdttIn799VdFRESoXbt2ql+/vrp166ajR49KunQ1ktmzZyslJUUXL17UZ599ZrttD1xWuXJlLVmyRGXLlvX6a7/++usaOHCg11/XF1w9Pr6etLQ0TZo0SUOHDnX2/5fvqbxz504VLVrUeZuzW2+9VXv37s3xClD+0K5dO33xxRduXaHDFZGRkZo9e7buvPNOr76up7xxXiy5dkz8VzmNGQCs16NHD02aNMmtK3S4IjY2VgsWLFCjRo28+rre4s3PhnI6L7rWuVVOY6Y/ORwOjR8/Xr169fL6a9evX1+LFy9W0aJFvf7aAAAA3kIxBxAEhgwZogcffFA1atS44rmJEyeqXLlyuv3223N8DSu/sM/JHXfcoZUrV3rt5Lp27dpatmyZbQs5JNc/yHRlurffflu33HLLVe+3ndNzly1btkwnT5609Mv/vn376uuvv/baF4733XefVq5cedX2EsgqVKigDRs2KDk5WefPn7/iPt8pKSm699571bdvX9t+WIWr69Spk5YuXarq1at75fWaNGmiVatWqXnz5l55Pbvr1q2bypYtq6SkJH344YfXnO7dd9/V/fff78dkrnE4HBo5cqQ+/PBDFSlSxCuv+dhjj2n58uUuFcTYWUJCgvbv36+1a9fqyy+/1Lhx4/TZZ59JkjIyMrRgwQKNHz9e69atU5kyZfTUU09Jkrp37667775bzZs3V/PmzZ23EwPsqlq1alq1apXat2/vldeLi4vTV199pf79+9vykvJX406Rl3Sp769Tp47+/ve/Z/tSfufOnYqNjdXrr7+uRo0a6dZbb9XChQslSVWqVNHx48e1bNkySdLs2bN15swZ7dmzx8drd3333Xefli9frjp16njl9RISErRixQq1bt3aK69nJ9c7Jr6anMYMAPbQo0cPLVq0SBUrVvTK67Vo0UKrV69W48aNvfJ6vuDNz4Yk18+LLstpzPS38PBwjRs3ThMmTHD7lszX8uSTT+rHH39UiRIlvPJ6AAAAvkIxB2CxsmXL6tChQ8rIyJAkGWO0d+9elStXLtt05cqVy/ZB4u7du53T/PDDDxo1apQqVKigZs2aKSUlRRUqVNDRo0e1ePFi/e9//1OFChVUoUIFSVLdunWz3R9z165dWrFihf72t7/5eG09U7NmTS1fvlyvv/66xydt+fPn18CBA7V69eocixf84eabb1axYsWu+rdv3z6vLWfz5s364osv9O9//9ut5/5s0qRJ6tatm+VfcrVr105btmzRY4895vGvcUqUKKEPP/xQX331lS1/ie4t0dHR6ty5sz766CPnY2fOnNHdd9+t+++/3ye/8Ifv3XTTTVq3bp369u3r8S9zCxYsqBEjRuinn35StWrVvJzQe7zdR06bNk379u3Ta6+9pn79+l11mtdff107duzQsGHDchvfJxwOh7p27aotW7bk6svc8uXL65tvvtGUKVOy/TrPblw9NipUqJBiYmIkXbriUpcuXbR06VJJl46bWrZsqTJlyjjfvxUrVki69H6+/PLLWrdunZYtW6aaNWs6f4kP2FXJkiX1xRdf6OOPP1bJkiU9eo2wsDA9+uij2rJli+2K17zZ9//444/auHGj1q5dq2LFiumxxx5zPpeRkaE9e/aoZs2aWr16tf773/+qU6dOOnz4sGJiYjRz5kz1799fDRs21Lx581SzZk3Lj4Mva9CggVavXq2kpCQVKFDAo9eIiorSq6++qhUrVnitMMRbvHFe/GdXOya+lpzGDAD20bx5c23cuFH/+Mc/PL5yYeHChfXee+9p4cKFuuGGG7yc0D3++mzoMlfOi/4spzHTCg6HQz179tTmzZvVpk0bj1+ncuXKWrBggcaOHZvjFYwBAABsw5KbuwAh7Gr3V2revHm2e1s2bNjwivl27txpSpUqZQ4dOmSysrLMvffea0aNGnXFdLt27TIxMTHXXL6kbPfKNMaYf//73+aRRx65bk47OH36tBk9erSpVauWS/e+rFy5snnrrbfM8ePHLcnryfvo6v2irzfdmDFjTFxcnClfvrwpX768iYiIMMWLFzdjxozJ8bnLzpw5Y6Kjo83WrVtztT7etmfPHjNw4EBTsmRJl/aBW2+91cyYMcOcP3/ekrxX48n7mNP937dv324uXLhgjDHm/PnzpmPHjmbAgAHGmEvbsWnTpmbIkCF+yQnfO3r0qBk+fLipWLGiS22gbt26Zty4cSYlJcXq6E7e2rdyahdXkz9//ivuhzxixAjTsGHDK8ZGb+b0tm3btpl//etfpnDhwi7tA61btzb/+9//nOOFHVzvvXXl2OjgwYMmMzPTGGNMSkqKadq0qZk0aZIx5tJYUb16dXP69GljjDHDhw83bdu2NcYYc/bsWXPixAljzKX2VK9ePTN79myPcgJWOH/+vPnkk09M8+bNXeoDihcvbgYMGGB2795tdXRjjG+Pj//q4MGDJjo62vnvo0ePmrCwMJORkeF8rFGjRmb+/PlXzHvu3DlTuHBhs2HDBtv1AydOnDDvvPOOqVq1qkv7QI0aNcyoUaPMqVOnrI7u5Ivz4pyOiS9bvHixqVevXrbHchozGAcAe0pOTjZDhw41ZcuWdakfTEhIMJMmTTJpaWmW5LXys6Grudp50V/PrXIaM+3QN27evNn06dPHFCxY8Lrb3+FwmHvvvdfMnTvXef4ABKsyZcoYSaZMmTJWR7FMoLwHduhLXREoOS8LlO3vS4HyHgTKvmWHnPb4iQkQ4saPH6/u3bvr9ddfV6FChTR58mRJ0hNPPKH77rtP9913nypWrKghQ4bolltukXTpkpC9e/fO9bKzsrI0ZcoUTZs2Ldev5Q+FChVSYmKinnrqKR04cEBr1qzRmjVrdODAAZ0/f14REREqWbKkGjVqpIYNG6pcuXIBc/noy0qUKKGEhARNnz5d3bt31xdffKH4+HhVrlzZremeeuqpbJcHbtGihZ599lnnLWZyek6SPv30U9WrV89rt3bwlnLlyum1117TK6+8ot9//11r1qzR2rVrdeLECV28eFEFChTQDTfcoEaNGikhIUHFihWzOnKu9O7dW99++62Sk5PVunVrFSxYUDt27MjWPyxatEj//e9/FR4eroyMDLVq1UpJSUmSLt06YuXKlUpLS3NeZvrhhx/WwIEDrVwt5EKxYsX04osv6oUXXtDu3bud/eDhw4d14cIFRUREKD4+3tkPli5d2urIljh16pTS09Od6//VV1+paNGiio2NdU7z9ttva8aMGVqwYIGtr1TxV1WrVtXbb7+t4cOHa+vWrVqzZo3Wr1+vU6dOKTMzUwUKFFCVKlXUqFEjNWjQIKDW7TJXjo2++OILjR07Vnny5FFGRoYefvhhPf7445IujRUDBgxQ06ZNFRYWpjJlymjChAmSLt0nvEWLFgoLC1NWVpb++c9/6t5777VsXQF35cuXT506dVKnTp10/PhxrV27VqtXr9Yff/yhs2fPKm/evIqNjVWDBg3UsGFDVa1aVeHh4VbHzhVXj4/T0tJ08eJFZ783Y8YMNWjQwPl8sWLF1KpVK33//fdq27atdu3apV27djlvv3fo0CHnFdxeffVV3X777apUqZJ/VtINRYoU0bPPPqt//vOf2rt3r/NY4PKtRSIiIlS6dGk1bNhQDRs2VHx8fECcE+X2vDinY+L09HRVrVpV58+f1+nTpxUfH69HH31Uw4YNy3HMAGBPJUuW1IABA9S/f3/t3LnT+bnA0aNHdeHCBeXPn1/lypVz9oNxcXFWR3abtz4bcuW86GquN2ZarVatWnrvvff0zjvvaMuWLVqzZo02bNiglJQUZWZmKjIyUtWqVVPDhg3VoEEDFSpUyOrIAAAAHnEYY4zVIYBQkpaW5rxVSGpqqqKioixOdHWBktPuPH0ft23bpu7du+v48ePODzIvXwr5zx9m5jTdX12tYCOn55o2baqePXs6vxjLzfogu0B5HwMlJwJPbvetPxc5FS1a1FnkJP1fH1mvXj09/PDDOnv2rMLCwlS8eHGNHDlS9evXlyTt379fZcuWVcWKFZ2X142IiNAvv/zitZy4tkB5bwMlJxBIfHl8XLt2bT300EPKzMyUMUYVK1bUu+++67zdpCT98ccf+vvf/65jx44pLCxMgwYN0kMPPSRJ6tmzp5YuXaqMjAzdfPPNGjVqlPLmzUs/4AOB0r8GSk4A9mblZ0N79uzJ8bwop3Ora42Z9I2AfcXHx+vAgQMqU6aM9u/fb3UcSwTKexAofWmg5LwsULa/LwXKexAo+5YdclLMAfiZHRq+KwIlp90F2/sYbOtjlUB5HwMlJwJPoOxbgZIzEAXKexsoOYFAEmjtKtDyBopAeV8DJScAewu2viTY1gcIJoHyJa4vBcp7ECh9aaDkvCxQtr8vBcp7ECj7lh1yhvl9iQAAAAAAAAAAAAAAALimPFYHAEJZWlqa1RGuyc7ZAlUwvKfBsA52Y+f31M7ZEDzsvJ/ZOVswsfP7bOdsQDAIhDYWCBkDnZ3fYztnAxCYgqFfCYZ1AAA7sXO/audsCB523s/skI1iDsBCJUuWtDoC/Ijtjathv0Coow2AfQAIXbR/SOwHAEILfR4A4K8YGxDqaAM54zYrAAAAAAAAAAAAAAAANsKVOQA/i4yMVGpqqtUx3BIZGWl1hIAViNvbVewXngvE/YLtDW+iDYB9AAhdgdj+L6Mf8J5A3A/Y/gA8FYh9nqvoGwHAM4E4NtDnw5toA66jmAPwM4fDoaioKKtjwE/Y3rga9guEOtoA2AeA0EX7h8R+ACC00OcBAP6KsQGhjjbgOm6zAgAAAAAAAAAAAAAAYCMUcwAAAAAAAAAAAAAAANgIxRwAAAAAAAAAAAAAAAA2QjEHAAAAAAAAAAAAAACAjVDMAQAAAAAAAAAAAAAAYCMUcwAAAAAAAAAAAAAAANgIxRwAAAAAAAAAAAAAAAA2QjEHAAAAAAAAAAAAAACAjVDMAQAAAAAAAAAAAAAAYCMUcwAAAAAAAAAAAAAAANgIxRwAAAAAAAAAAAAAAAA2QjEHAAAAAAAAAAAAAACAjVDMAQAAAAAAAAAAAAAAYCMUcwAAAAAAAAAAAAAAANgIxRwAAAAAAAAAAAAAAAA2QjEHAAAAAAAAAAAAAACAjVDMAQAAAAAAAAAAAAAAYCN5rA4AAAAAAAAAAAAAhAJjjNLT073+ullZWc7/pqWlefW1IyMj5XA4vPqaCG2+aAe0AQQjijkAAAAAAAAAAAAAP0hPT1d0dLTPXv/QoUNef/3U1FRFRUV59TUR2nzZDmgDCCbcZgUAAAAAAAAAAAAAAMBGuDIHAAAAAAAAAAAA4GeHDx+27a/909LSVLJkSatjIATYtR3QBmAHFHMAAAAAAAAAAAAAfhYVFWXLL7EBf6IdANfGbVYAAAAAAAAAAAAAAABshGIOAAAAAAAAAAAAAAAAG6GYAwAAAAAAAAAAAAAAwEYo5gAAAAAAAAAAAAAAALARijkAAAAAAAAAAAAAG1uyZIkcDke2v+joaCUkJOidd95RRkaG1REBn6INIBTlsToAAAAAAAAAAAAAgOvr0qWL2rZtK2OMkpOTNW3aND333HPaunWrJkyYYHU8wOdoAwglFHMAAAAAAAAAAAAAASAhIUFdu3Z1/jsxMVHVq1fXxIkTNXToUBUvXtzCdIDv0QYQSrjNCgAAAAAAAAAAABCAoqKi1KRJExljtHPnTqvjAH5HG0AwC+lijq+++koOh4MKLQAAAAAAAAAAAASky19gx8bGWpwEsAZtAMEqpG+zsmHDBklSvXr1LE4CAAAAAAAAAAAA5Cw9PV3Hjh2TMUbJyckaN26c1q1bp8aNG6tq1apWxwN8jjaAUEIxh6T69etbGwQAAAAAAAAAAAC4jsGDB2vw4MHZHnvwwQc1evRoixIB/kUbQCgJ6duscGUOAAAAAAAAAAAABIpevXpp/vz5mjNnjt58803FxsZq//79yp8/v3Oazp07q2PHjtnmO3HihEqVKqWPPvrI35EBr6INIJSEbDHHmTNntGvXLklcmQMAAAAAAAAAAAD2V6VKFd1xxx1q06aN+vbtq6+//lqrVq3Sk08+6ZxmzJgx+vnnnzVjxgznY3369FGzZs30yCOPWBEb8BraAEJJyBZzbNy4UcYYRUREqHr16lbHAQAAAAAAAAAAANzStGlTPfroo/r000+1bNkySVJsbKwmTZqkp59+WgcPHtTMmTO1ZMkSjRs3zuK0gPfRBhDMQraY4/ItVmrWrKm8efNanAYAAAAAAAAAAABwX1JSksLDwzVo0CDnY3fffbc6duyorl27KjExURMnTlTRokUtTAn4Dm0AwSrkiznq1atncRIAAAAAAAAAAADAM5UrV1bnzp21cOFCLV261Pn4yJEjtWPHDrVp00b33HOPhQkB36INIFiFfDFH/fr1rQ0CAAAAAAAAAAAA5MLAgQMVFhaW7coEUVFRqlixourUqWNhMsA/aAMIRnmsDmCFrKwsbdq0SVLuizkaNWqk5ORkL6QCAAAAAAAAAABAMMvKyvJovhYtWsgYc83na9SooczMTE9j5ahKlSoKC7P/78MPHTrk/G98fLzFaZATT9oBbeD6aAP2FBcXp9WrV3s0b0gWc+zYsUPp6emScn+bleTkZB04cMAbsQAAAAAAAAAAAABbufwFcaDIysriuzt4FW0AVgnJYo7Lt1gpX768ChcunKvXiouL80IiAAAAAAAAAAAABLusrKyA+2K4VKlSAXNVgqysLIWFhalUqVJWx0EOAq0d0AaQG7mpJwjpYo7cXpVDkseXRAEAAAAAAAAAAEBoSUtLU3R0tN+Wt2TJkly/xvbt2xUVFZX7MD4WHx+vAwcOqFSpUtq/f7/VcZADf7YD2gACmf1LiHzgcjFH/fr1rQ0CAAAAAAAAAAAAAADwFyFdzOGNK3MAAAAAAAAAAAAAAAB4U8gVc5w8eVL79u2TxJU5AAAAAAAAAAAAAACA/YRcMcfatWslScWKFdMNN9xgcRoAAAAAAAAAAAAAAIDsQq6Y44cffpAkNW/eXA6Hw+I0AAAAAAAAAAAAAAAA2YVUMUdGRoamT58uSerSpYvFaQAAAAAAAAAAAADXnDt3Tg888ICqVq2qevXq6c4779SOHTuumG737t0KDw9X/fr1nX87d+60IDHgme3bt6tp06aqWrWqbrzxRm3ZsuWa0xpjdPvtt6tw4cLOx3JqA6mpqWrdurWKFSuWbR7AjvJYHcBfzp49qz59+mjXrl2qXbu22rdvb3UkAAAAAAAAAAAAwGW9evVSmzZt5HA49N577+mJJ57QkiVLrpiuYMGCWr9+vd/zAd7Qu3dv9erVS927d9fMmTPVvXt3rVq16qrTvvPOO6pUqZLWrl2b7fFrtYG8efOqX79+io2NVYsWLXyQHvCeoL8yxxdffKGGDRuqePHimjx5sooXL65PPvlEYWFBv+oAAAAAAAAAAAAIEvnz51fbtm3lcDgkSU2aNNHu3butDQV42ZEjR7R69Wp17dpVkvTQQw9p3759V70KzZYtW/TVV1/ppZdecvn1IyIirriSB2BXQV/RMGfOHG3evFklS5ZUnz59tG7dOtWqVcvqWAAAAAAAAAAAAIDH3n33Xd1///1XfS4tLU033nijEhIS9MorrygzM9PP6QDP7Nu3T6VKlVKePJduMOFwOFSuXDnt3bs323QXL15Uz549NX78eIWHh1/xOrQBBIOgL+aYNGmSzp8/r507d+q9995TmTJlrI4EAAAAAAAAAAAAeOz111/Xjh07NGzYsCueK1WqlA4cOKBVq1ZpwYIFWrp0qd566y0LUgK+M2TIED344IOqUaPGFc/RBhAsgr6YAwAAAAAAAAAAAAgWI0eO1KxZszR37lxFRkZe8XxERIRKlCghSYqNjVWPHj20dOlSf8cEPFK2bFkdOnRIGRkZkiRjjPbu3aty5cplm+6HH37QqFGjVKFCBTVr1kwpKSmqUKGCjh49ShtA0KCYAwAAAAAAAAAAAAgAb7/9tmbMmKH58+ercOHCV53myJEjunjxoiTp/PnzmjVrlho0aODHlIDnSpQooYSEBE2fPl2S9MUXXyg+Pl6VK1fONt3SpUu1Z88e7d69Wz/99JMKFSqk3bt3q3jx4rQBBA2KOQAAAAAAAAAAAACb279/v55//nmdOnVKLVu2VP369XXTTTdJkgYNGqRx48ZJkn766Sc1aNBA9erVU0JCguLi4jRw4EArowNuGT9+vMaPH6+qVavqjTfe0OTJkyVJTzzxhGbPnn3d+a/XBurWraubb75ZKSkpio+P16OPPuqzdQFyw2GMMVaHAAAAAAAAAAAAAIJdWlqaoqOjJUmpqamKioqyONHVBUrOP4uPj9eBAwdUpkwZ7d+/3+o4yEEg7F+BkPGvaAPBhytzAAAAAAAAAAAAAAAA2AjFHAAAAAAAAAAAAAAAADaSx+oAAAAAAAAAAAAAQKhJS0uzOsI12Tkbgotd9zW75kJooZgDAAAAAAAAAAAA8LOSJUtaHQGwHO0AuDZuswIAAAAAAAAAAAAAAGAjXJkDAAAAAAAAAAAA8IPIyEilpqZaHcMtkZGRVkdAkAm0dkAbgFUo5gAAAAAAAAAAAAD8wOFwKCoqyuoYgKVoB4BruM0KAAAAAAAAAAAAAACAjVDMAQAAAAAAAAAAAAAAYCMUcwAAAAAAAAAAAAAAANgIxRwAAAAAAAAAAAAAAAA2QjEHAAAAAAAAAAAAAACAjVDMAQAAAAAAAAAAAAAAYCMUcwAAAAAAAAAAAAAAANgIxRwAAAAAAAAAAAAAAAA2QjEHAAAAAAAAAAAAAACAjVDMAQAAAAAAAAAAAAAAYCMUcwAAAAAAAAAAAAAAANgIxRwAAAAAAAAAAAAAAAA2QjEHAAAAAAAAAAAAAACAjVDMAQAAAAAAAAAAAAAAYCMUcwAAAAAAAAAAAAAAANgIxRwAAAAAAAAAAAAAAAA2QjEHAAAAAAAAAAAAAACAjeSxOgAAAAAAAAAAAACA0GCMUXp6utdfNysry/nftLQ0r752ZGSkHA6HV18ToYs2AFc5jDHG6hAAAAAAAAAAAAAAgl9aWpqio6OtjuGW1NRURUVFWR0DQYI2AFdxmxUAAAAAAAAAAAAAAAAb4TYrAAAAAAAAAAAAAPzu8OHDtv21f1pamkqWLGl1DAQ52gByQjEHAAAAAAAAAAAAAL+Lioqy7RfZgD/QBpATbrMCAAAAAAAAAAAAAABgIxRzAAAAAAAAAAAAAAAA2AjFHAAAAAAAAAAAAAAAADZCMQcAAAAAAAAAAAAAAICNUMwBAAAAAAAAAAAAAABgIxRzAAAAAAAAAAAAALCtJUuWyOFwZPuLjo5WQkKC3nnnHWVkZFgdEfA52kHoyWN1AAAAAAAAAAAAAAC4ni5duqht27Yyxig5OVnTpk3Tc889p61bt2rChAlWxwP8gnYQOijmAAAAAAAAAAAAAGB7CQkJ6tq1q/PfiYmJql69uiZOnKihQ4eqePHiFqYD/IN2EDq4zQoAAAAAAAAAAACAgBMVFaUmTZrIGKOdO3daHQewBO0geAVVMceCBQuy3SNo8eLF15zWGKPGjRs7p61Tp44fkwIAAAAAAAAAAADIrctfXsfGxlqcBLAO7SA4BdVtVtatW5ft37/++qtatmx51WlnzJihVatWOf9dv359X0YDAAAAAAAAAAAAkAvp6ek6duyYjDFKTk7WuHHjtG7dOjVu3FhVq1a1Oh7gF7SD0BFUxRzr16+XJNWsWVO//vqrtmzZctXpzp07pwEDBihfvnwqXbq0du/erQYNGvgxKQAAAAAAAAAAAAB3DB48WIMHD8722IMPPqjRo0dblAjwP9pB6Aiq26xcvjJHt27dJOmaxRz/+c9/tGfPHiUmJurMmTOSuDIHAAAAAAAAAAAAYGe9evXS/PnzNWfOHL355puKjY3V/v37lT9/fuc0nTt3VseOHbPNd+LECZUqVUofffSRvyMDXkc7CB1BU8xx9uxZ/f7775KkDh06KDIy8qrFHEePHtWwYcNUpEgRde/eXcePH5dEMQcAAAAAAAAAAABgZ1WqVNEdd9yhNm3aqG/fvvr666+1atUqPfnkk85pxowZo59//lkzZsxwPtanTx81a9ZMjzzyiBWxAa+iHYSOoCnm2LhxozIzMxUTE6NKlSqpVq1aOn78uA4fPpxtusGDByslJUVJSUnau3evJKlcuXKKjY21IjYAAAAAAAAAAAAADzRt2lSPPvqoPv30Uy1btkySFBsbq0mTJunpp5/WwYMHNXPmTC1ZskTjxo2zOC3gG7SD4BU0xRzr16+XJNWrV0+SVLduXUnZb7Xy22+/6f3331elSpXUp08f5zwNGjTwa1YAAAAAAAAAAAAAuZeUlKTw8HANGjTI+djdd9+tjh07qmvXrkpMTNTEiRNVtGhRC1MCvkU7CE5BU8yxbt06Sf93u5SrFXO8+OKLysjI0BtvvKF8+fI5izm4xQoAAAAAAAAAAAAQeCpXrqzOnTtr4cKFWrp0qfPxkSNHaseOHWrTpo3uueceCxMCvkc7CE55rA7gLX8tzPhrMceiRYv0zTffqGnTpurQoYOk/ysAyc2VORo1aqTk5GSP5wcAAAAAAAAAAABCRVZWltdfc+DAgZoxY4YGDRqkxYsXS5KioqJUsWJF1alTJ9evX6VKFYWFBc1v5GExX7QBybftgDbgubi4OK1evdqjeYOimCMrK0ubNm2S9H/FHJd3yC1btigrK0vPP/+8JOmtt96SJKWkpGj37t3Z5vFEcnKyDhw44PH8AAAAAAAAAAAAAK6tRYsWMsZc8/kaNWooMzPTZ8s/dOiQz14bcJWV7YA2YI2gKObYtm2b0tPTlTdvXtWqVUuSVLRoUZUuXVpbtmzRtGnTtH79enXq1ElNmjSRdOlKHsYYFSlSROXLl/d42XFxcV5ZBwAAAAAAAAAAACDYZWVlBdwXw6VKleKqBPAa2kBoyU09QVAUc1y+XUrNmjWVL18+5+N169bVd999pxdeeEEREREaNmzYFfPk5qockjy+JAoAAAAAAAAAAAAQatLS0hQdHW11DLds375dUVFRVsdAkKANwFVBUcyxfv16SVcWZlwu5jh+/LheeOEF3XDDDVfM06BBAz+lBAAAAAAAAAAAAOAvS5YssToCYDnaQeAKimKOa11l4/bbb9eaNWuUN29eDRw4MNtz1yoAAQAAAAAAAAAAAAAAsFJQFHNcqzCjdevWat269RXTX7hwQVu2bJHElTkAAAAAAAAAAAAAAIC9hFkdILf279+vY8eOSXL9Khu//vqrLl68qPz586t69eo+TAcAAAAAAAAAAAAAAOCegC/muHxVjvLly6tw4cJuzVOrVi3lyRMUFycBAAAAAAAAAAAAAABBwmGMMVaHAAAAAAAAAAAAABD80tLSFB0dLUlKTU1VVFSUxYmuLlByIvAEyr4VKDmDWcBfmQMAAAAAAAAAAABAcHrmmWdUoUIFORwO59X3/2r37t1q0aKFYmJiVL9+/Sue37Rpk1q0aKEaNWqoRo0amjVrlm9DAz5y7tw5PfDAA6patarq1aunO++8Uzt27Lhiut27dys8PFz169d3/u3cudOCxMgN7jECAAAAAAAAAAAAwJY6dOigvn37qlmzZtecplChQnrttdd0+vRpDRw4MNtz6enpuv/++zVt2jQ1a9ZMmZmZOnHihK9jAz7Tq1cvtWnTRg6HQ++9956eeOIJLVmy5IrpChYseM0CKAQGrswBAAAAAAAAAAAAwJZuu+02xcfH5zhNbGysmjVrdtXbQHz88cdq0qSJsxgkPDxcxYsX90lWwNfy58+vtm3byuFwSJKaNGmi3bt3WxsKPkMxBwAAAAAAAAAAAICg9OuvvyoiIkLt2rVT/fr11a1bNx09etTqWIBXvPvuu7r//vuv+lxaWppuvPFGJSQk6JVXXlFmZqaf0yG3KOYAAAAAAAAAAAAAEJQyMjK0YMECjR8/XuvWrVOZMmX01FNPWR0LyLXXX39dO3bs0LBhw654rlSpUjpw4IBWrVqlBQsWaOnSpXrrrbcsSIncoJgDAAAAAAAAAAAAQFAqV66cWrZsqTJlysjhcKhr165asWKF1bGAXBk5cqRmzZqluXPnKjIy8ornIyIiVKJECUmXbkPUo0cPLV261N8xkUsUcwAAAAAAAAAAAAAISh07dtSqVauUkpIiSZozZ47q1atncSrAc2+//bZmzJih+fPnq3Dhwled5siRI7p48aIk6fz585o1a5YaNGjgx5TwBoo5AAAAAAAAAAAAANhS7969FR8fr/3796t169aqXLmyJOmJJ57Q7NmzJUnp6emKj4/Xww8/rF9//VXx8fHq37+/pEtX5hgwYICaNm2qunXratGiRRo3bpxl6wPkxv79+/X888/r1KlTatmyperXr6+bbrpJkjRo0CDnvv3TTz+pQYMGqlevnhISEhQXF6eBAwdaGR0ecBhjjNUhAAAAAAAAAAAAAAS/tLQ0RUdHS5JSU1MVFRVlcaKrC5ScCDyBsm8FSs5gxpU5AAAAAAAAAAAAAAAAbCSP1QEAAAD+X3t3bMQgDEVBEKU0QP9FQipXYI+dWDewW8EL9LObEQAAAADwPOd5rp7wVnkb91F+Z+VtTyHmAAAAAAAAAP7uOI7VE2ApN8AnvlkBAAAAAAAAAAgZc865egQAAAAAAABwf3PO7bqu1TN+su/7NsZYPYObcAN8S8wBAAAAAAAAABDimxUAAAAAAAAAgBAxBwAAAAAAAABAiJgDAAAAAAAAACBEzAEAAAAAAAAAECLmAAAAAAAAAAAIEXMAAAAAAAAAAISIOQAAAAAAAAAAQsQcAAAAAAAAAAAhYg4AAAAAAAAAgBAxBwAAAAAAAABAiJgDAAAAAAAAACBEzAEAAAAAAAAAECLmAAAAAAAAAAAIEXMAAAAAAAAAAISIOQAAAAAAAAAAQsQcAAAAAAAAAAAhYg4AAAAAAAAAgBAxBwAAAAAAAABAiJgDAAAAAAAAACBEzAEAAAAAAAAAECLmAAAAAAAAAAAIEXMAAAAAAAAAAISIOQAAAAAAAAAAQsQcAAAAAAAAAAAhYg4AAAAAAAAAgJAX9cxF8AYMZIMAAAAASUVORK5CYII=" + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Initialize register\n", + "var = [\"B\", \"E\", \"A\", \"J\", \"M\"]\n", + "qr = [QuantumRegister(1, name=v) for v in var]\n", + "qc_ba = QuantumCircuit(*qr, name=\"State preparation\")\n", + "# Specify control qubits\n", + "# P(B)\n", + "qc_ba.ry(theta_B, qr[0])\n", + "# P(E)\n", + "qc_ba.ry(theta_E, qr[1])\n", + "# P(A|B,E)\n", + "qc_ba.mcry(theta_E, [qr[0][0], qr[1][0]], qr[2])\n", + "# P(A|-B,E)\n", + "qc_ba.x(qr[0])\n", + "qc_ba.mcry(theta_A_BnE, [qr[0][0], qr[1][0]], qr[2])\n", + "qc_ba.x(qr[0])\n", + "# P(A|B,-E)\n", + "qc_ba.x(qr[1])\n", + "qc_ba.mcry(theta_A_nBE, [qr[0][0], qr[1][0]], qr[2])\n", + "qc_ba.x(qr[1])\n", + "# P(A|-B,-E)\n", + "qc_ba.x(qr[0])\n", + "qc_ba.x(qr[1])\n", + "qc_ba.mcry(theta_A_nBnE, [qr[0][0], qr[1][0]], qr[2])\n", + "qc_ba.x(qr[0])\n", + "qc_ba.x(qr[1])\n", + "# P(J|A)\n", + "qc_ba.cry(theta_J_A, qr[2], qr[3])\n", + "# P(M|A)\n", + "qc_ba.cry(theta_M_A, qr[2], qr[4])\n", + "# P(J|-A) + P(M|-A)\n", + "qc_ba.x(qr[2])\n", + "qc_ba.cry(theta_J_nA, qr[2], qr[3])\n", + "qc_ba.cry(theta_M_nA, qr[2], qr[4])\n", + "qc_ba.x(qr[2])\n", + "# Draw circuit\n", + "qc_ba.draw(\"mpl\", style=\"bw\", plot_barriers=False, justify=\"none\", fold=-1)" + ] + }, + { + "cell_type": "markdown", + "id": "b8cc65c8d0c64c91", + "metadata": { + "collapsed": false + }, + "source": [ + "## 3. How to Run Rejection Sampling" + ] + }, + { + "cell_type": "markdown", + "id": "eff9038bd1a6a91e", + "metadata": { + "collapsed": false + }, + "source": [ + "### 3.1. Set up\n", + "\n", + "Rejection sampling is a basic technique used in probabilistic computing for generating observations from a distribution. It's particularly useful when direct sampling from the desired distribution is difficult. The core idea is to use a simpler distribution (referred to as the proposal distribution) from which we can easily sample, and then to \"reject\" or \"accept\" these samples based on a certain criterion (evidence) so that the accepted samples follow the desired target distribution. \n", + "\n", + "Quantum rejection sampling adapts the classical rejection sampling method to the quantum computing context, utilizing quantum algorithms and states to perform efficient sampling. Once the state is prepared by the given quantum circuit representing the Bayesian network, it is measured, resulting in the collapse to one of its possible outcomes. This step is analogous to drawing a sample in classical rejection sampling. However, quantum rejection sampling primarily focuses on post-selection, where only specific measurement outcomes that meet desired criteria, here evidence, are retained, and others are disregarded.\n", + "\n", + "In this implementation, Grover's algorithm is employed for amplitude amplification. This step is designed to increase the probability amplitudes of the desired outcomes, thereby reducing the number of samples needed. The efficiency of quantum rejection sampling lies in its utilization of quantum parallelism, which allows for the simultaneous evaluation of multiple probabilities, and quantum interference, which can be used to increase the likelihood of obtaining desired outcomes.\n", + "\n", + "Quantum rejection sampling is particularly beneficial in complex or high-dimensional probability distribution scenarios, where classical computers face challenges. Its applications extend to quantum machine learning, probabilistic modeling, and other areas of quantum computing. \n", + "\n", + "To use the `QBayesian` class, instantiate it with a quantum circuit that represents the Bayesian network. You can then use the rejection sampling method to estimate probabilities given evidence." + ] + }, + { + "cell_type": "markdown", + "id": "c3fd5b7532b845c4", + "metadata": { + "collapsed": false + }, + "source": [ + "#### 3.1.1 Two Node Bayesian Network Example\n", + "If we want to carry out a rejection sampling with X=1 as evidence, we can do this in the following way:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "1e602fda98a6356d", + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-03-15T12:25:44.414966Z", + "start_time": "2024-03-15T12:25:44.300268Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": "
", + "image/png": "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98z92eOPP65PPvlE6enp9g0B77//vp588kn7fRE1a9bUrl271L59e4fHzc/PV7t27XT8+HH9+OOP9tWzrKwshYSE6MiRIzp48KACAwMlSampqcrKylKTJk1K3TRRqCL3zP1Zdna2fH19y71uDQCoPqPnuboC4A8Lxlfv+I5mD6cvs27evFn9+/e3BzlJmjVrlpo1a6YtW7YoOjpaNptNr732WoXG9fDw0Icffiir1aqePXtqzJgxmjhxojp16qT4+HjNmDHDHuQkafLkybruuuv09ddfOzsVAAAAw3L6MmtqamqRF9bv379fycnJmjNnjkJDQyVJX375ZYWeR1eoT58+2rZtm6KiorR06VLl5eWpQ4cOmj17toYOHepsyQAAAH85Toe53Nxc1ahRw/7z5s2bZTKZiry5ISgoSCtWrHBq/JCQEMXExJTbb9GiRVq0aJFDYwYGBsrJq8oAAABuyenLrM2bN9e+ffvsP3/77bdq0KCBOnbsaG87deqU6tSpU7kKAQAAUCqnV+YGDhyod999V//85z/l7e2t1atXa8SIEUX6xMfHs2MUAACgGjkd5iZPnqyVK1fqjTfekCQ1adJE//rXv+zHT5w4oe+//15PPvlk5asEAABAiZwOc/7+/vr111+1fv16SVLPnj2LbJvNyMjQa6+9pvDw8MpXCQAAgBI5Heaky8+Ru+OOO0o8dv311+v666+vzPAAAAAoh9u9zgsAAACOq9TKXEFBgaKjo7Vu3TqlpKQoNze3WB+TyWS/FAsAAICq5XSYO3funMLCwvTjjz/KZrPJZDIVeYZb4c8mk6lKCgUAAEBxTl9mfeWVVxQXF6fp06crIyNDNptN06ZNU2pqqpYuXaqgoCDdf//9Ja7WAQAAoGo4Hea++uordevWTS+++KIaNGhgb/fz89P999+vjRs3at26dRV+NysAAAAc53SYS0pKUrdu3f4YyGwusgrXvHlzDRo0SIsXL65chQAAACiV02Gudu3aMpv/+Livr69SU1OL9PH391dSUpLz1QEAAKBMToe5li1bFglqN954ozZs2GBfnbPZbFq/fr2aNGlS+SoBAABQIqfDXL9+/bRx40bl5+dLkkaOHKmkpCR1795dkyZNUmhoqPbu3avIyMgqKxYAAABFOf1oktGjR6thw4Y6efKkmjRpokceeUR79uzRe++9p71790qS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" + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qiskit_machine_learning.algorithms import QBayesian\n", + "from qiskit.visualization import plot_histogram\n", + "\n", + "evidence = {\"X\": 1}\n", + "# Initialize QBayesian\n", + "qb_2n = QBayesian(circuit=qc_2n)\n", + "# Sampling\n", + "samples = qb_2n.rejection_sampling(evidence=evidence)\n", + "plot_histogram(samples)" + ] + }, + { + "cell_type": "markdown", + "id": "166108a390743bd4", + "metadata": { + "collapsed": false + }, + "source": [ + "We can also set the threshold to accept the evidence. For example, if set to 0.9, this means that each evidence qubit must be equal to the value of the evidence variable at least 90% of the time in order to be accepted. Sometimes we can also improve our result by setting the threshold for acceptance of the evidence higher:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "a6fc4d5d394d301a", + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-03-15T12:25:44.544878Z", + "start_time": "2024-03-15T12:25:44.427867Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": "
", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAnMAAAG8CAYAAAC15iPyAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/SrBM8AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA9UElEQVR4nO3deVyVZf7/8fdZENwANQU3MNI0SwVLUnPchcKsKUrMyqzvaItOi441Wj/RmUatrPTbMmP6zfxWlpRTaam44lKU5pIz5UI4CMqiiIKYInDO7w+/nCS2w+HAOXe9no/HPB6d677OdT6XzOHx5rrv675NdrvdLgAAABiS2dMFAAAAwHWEOQAAAAMjzAEAABgYYQ4AAMDACHMAAAAGRpgDAAAwMMIcAACAgRHmAAAADMzq6QKMwmazKTMzU82bN5fJZPJ0OQAA4FfObrfr7NmzateunczmqtffCHNOyszMVMeOHT1dBgAA+I3JyMhQhw4dqjxOmHNS8+bNJV36B/X39/dwNQAA4NeuoKBAHTt2dGSQqhDmnFR2atXf358wBwAAGkxNl3exAQIAAMDACHMAAPzKvPHGG+rUqZP8/Px04403aufOnVX2LS4u1l/+8hddddVV8vPzU69evbRu3boGrBZ1RZgDAOBXZMWKFZoyZYri4+O1Z88e9erVS9HR0Tpx4kSl/Z977jktWrRIr732mn744Qc98sgjuuOOO7R3794GrhyuMtntdrunizCCgoICBQQEKD8/n2vmAABe68Ybb1SfPn30+uuvS7p0a62OHTvqj3/8o/785z9X6N+uXTs9++yzmjRpkqMtNjZWjRs31nvvvddgdaMiZ7MHK3MAAPxKXLx4Ubt379bw4cMdbWazWcOHD1dycnKl7ykqKpKfn1+5tsaNG2vHjh31WivchzAHAMCvRG5urkpLSxUUFFSuPSgoSNnZ2ZW+Jzo6Wq+88opSUlJks9m0YcMG/fOf/1RWVlZDlAw3IMwBAPAbtnDhQnXp0kXdunVTo0aNNHnyZD344IPVPnEA3oWfFAAAvxJXXHGFLBaLcnJyyrXn5OQoODi40ve0bt1an376qc6dO6ejR4/q4MGDatasmcLCwhqiZLgBYQ4AgF+JRo0a6frrr9emTZscbTabTZs2bVK/fv2qfa+fn5/at2+vkpISrVy5Urfffnt9lws34QkQAAD8ikyZMkUPPPCAbrjhBkVGRmrBggU6d+6cHnzwQUnSuHHj1L59e82dO1eS9M033+j48eMKDw/X8ePHNWvWLNlsNj399NOenAZqgTAHAMCvSFxcnE6ePKmZM2cqOztb4eHhWrdunWNTRHp6ernr4S5cuKDnnntOR44cUbNmzRQTE6N3331XgYGBHpoBaov7zDmJ+8wBAICGxH3mAAAAfgMIcwAAAAZGmAMAADAwwhwAAICBEeYAAAAMjDAHAABgYIQ5AAAAAyPMAQAAGBhhDgAAwMAIcwAAAAZGmAMAADAwwhwAAICBEeYAAAAMjDAHAABgYIQ5AAAAAyPMAQAAGBhhDgAAwMAIcwAAAAZGmAMAADAwwhwAAICBWT1dAAAAzpqwwNMVAD9b/KSnK7iElTkAAAADI8wBAAAYGGEOAADAwAhzAAAABkaYAwAAMDDCHAAAgIER5gAAAAyMMAcAAGBghDkAAAADI8wBAAAYGGEOAADAwAhzAAAABkaYAwAAMDDCHAAAgIER5gAAAAyMMAcAAGBghDkAAAADI8wBAAAYGGEOAADAwAhzAAAABkaYAwAAMDDCHAAAgIER5gAAAAyMMAcAAGBghDkAAAADI8wBAAAYGGEOAADAwAhzAAAABkaYAwAAMDDCHAAAgIER5gAAAAzMa8Pcrl27FBMTo8DAQDVt2lR9+/ZVQkJCrcbIzMzUE088oe7du6tp06YKCgrSgAED9O6776q0tLSeKgcAAGg4Vk8XUJktW7YoOjpafn5+GjNmjJo3b66VK1cqLi5OGRkZmjp1ao1jHDlyRDfeeKNOnTql6OhojRo1SgUFBfr00081btw4bd68WUuXLm2A2QAAANQfk91ut3u6iMuVlJSoW7duOnbsmL7++muFh4dLkvLz8xUZGam0tDQdPnxYoaGh1Y7z2GOP6e9//7sWLFigJ554wtF+5swZ9erVS+np6UpLS6txnDIFBQUKCAhQfn6+/P39XZ4fAMB1ExZ4ugLgZ4ufrN/xnc0eXneadfPmzUpNTdXYsWMdQU6SAgICNGPGDF28eFHLli2rcZwjR45IkmJiYsq1BwYGasCAAZKk3Nxc9xUOAADgAV4X5pKSkiRJUVFRFY5FR0dLkrZu3VrjONddd50kac2aNeXaz5w5oy+//FLBwcHq3r17HasFAADwLK+7Zi4lJUWS1KVLlwrHgoOD1axZM0ef6kybNk2rV6/WU089pXXr1qlnz56Oa+aaNGmiTz75RI0bN67y/UVFRSoqKnK8LigokCQVFxeruLhYkmQ2m2WxWFRaWiqbzeboW9ZeUlKiy89iWywWmc3mKtvLxi1jtV768ZSUlDjV7uPjI5vNVm5zh8lkktVqrbK9qtqZE3NiTszJG+ckmQR4i4b4PjnD68Jcfn6+pEunVSvj7+/v6FOdoKAgJScn67777tPatWu1bt06SVLjxo31yCOPqFevXtW+f+7cuZo9e3aF9vXr16tJkyaSpJCQEEVERGj//v1KT0939Onatau6deumnTt36uTJk4728PBwhYaGatu2bTp79qyjvV+/fmrTpo3Wr19f7gc3ZMgQNW7cuMLqYkxMjM6fP68tW7Y42qxWq0aOHKnc3FwlJyc72ps3b66hQ4cqIyND+/btc7S3bt1a/fv3V0pKig4dOuRoZ07MiTkxJ2+ek8Q1y/Ae9f192r17t1N1eN0GiKioKG3YsEEpKSnq3LlzhePt27dXYWFhjYHuxx9/1KhRo9SsWTO9+uqrCg8P15kzZ/Tee+/pueeeU2RkpLZv3y6LxVLp+ytbmevYsaNyc3MdFyF6+i/UX+Nf3cyJOTEn5lTdnCYuZGUO3mPR4/X7fcrLy1OrVq1q3ADhdStzZStyVYW1goICtWjRosZxxo8fr6NHj+rIkSMKDg6WJDVr1kx//vOflZOTowULFujDDz/UvffeW+n7fX195evrW6Hdx8dHPj4+5dosFkulofDn0wLOtf9yXFfazWazzOaKl0JW1V5V7cyJOdW2nTkxJ6n+5wR4E099nyp8nlO9GlDZtXKVXReXnZ2twsLCSq+nu9zZs2f15Zdf6pprrnEEucsNGTJEkrR37143VAwAAOA5XhfmBg0aJOnStWm/lJiYWK5PVS5evCip6luPlF3PUdnKGwAAgJF4XZgbNmyYwsLCtHz58nIXD+bn52vOnDlq1KiRxo0b52jPysrSwYMHy52WbdWqlbp27ar09HQtWbKk3PhnzpzR/PnzJf28QgcAAGBUXhfmrFarlixZIpvNpoEDB2rixImaOnWqevXqpcOHD2vOnDnq1KmTo//06dN1zTXX6JNPPik3zquvviqr1aoJEyZo+PDhmjZtmv7whz/o6quv1sGDBxUbG6vhw4c38OwAAADcy+s2QEiXVsx27Nih+Ph4rVixQsXFxerRo4deeOEFxcXFOTXGLbfcoq+++kovvfSSduzYoa1bt8rPz0/XXHONZs6cqUcffbSeZwEAAFD/vO7WJN6KZ7MCgOfxbFZ4E57NCgAAgDojzAEAABgYYQ4AAMDACHMAAAAGRpgDAAAwMMIcAACAgRHmAAAADIwwBwAAYGCEOQAAAAMjzAEAABgYYQ4AAMDACHMAAAAGRpgDAAAwMMIcAACAgRHmAAAADIwwBwAAYGCEOQAAAAMjzAEAABgYYQ4AAMDACHMAAAAGRpgDAAAwMMIcAACAgRHmAAAADIwwBwAAYGCEOQAAAAMjzAEAABgYYQ4AAMDACHMAAAAGRpgDAAAwMMIcAACAgRHmAAAADMzlMNe9e3e9+uqrOnXqlDvrAQAAQC24HObS09P1pz/9SR06dNA999yjzZs3u7MuAAAAOMHlMJedna0333xT1113nVasWKERI0aoc+fOmjdvnrKzs91ZIwAAAKrgcphr1qyZHn74Ye3atUvfffedHnvsMZ0+fVozZsxQSEiI7rzzTq1du1Z2u92d9QIAAOAybtkA0aNHD7322mvKzMzUu+++qwEDBuizzz7TrbfeqtDQUM2ePVvHjx93x0cBAADgMm7dzerr66vo6GjFxMQoODhYdrtdx44d0+zZsxUWFqZJkybpp59+cudHAgAA/Ka5LcytX79eo0ePVocOHfTMM8/IZDLp//2//6cff/xRCQkJ6t27t/7xj39o0qRJ7vpIAACA3zxrXd58/Phxvf3221q6dKmOHj0qSYqKitLDDz+sUaNGyWKxSJLCwsJ01113adSoUfrss8/qXjUAAAAk1SHM3XrrrUpMTFRpaamCgoL0zDPPaOLEierUqVOV7+nfv7/WrFnj6kcCAADgF1wOc2vWrNHQoUP18MMP64477pDVWvNQo0aNUrt27Vz9SAAAAPyCy2Hu8OHD6ty5c63ec9111+m6665z9SMBAADwCy5vgJgzZ45WrVpVbZ/PP/9cDz30kKsfAQAAgBq4HObeeecd7du3r9o+3333nZYtW+bqRwAAAKAGbr3P3C9duHDBqWvpAAAA4Jo6JS2TyVRpu91uV0ZGhtauXcuGBwAAgHpUq5U5s9ksi8XiuH/crFmzHK8v/5/VatWVV16pPXv2aMyYMfVSOAAAAGq5Mjdw4EDHaty2bdsUEhJS6X3lLBaLWrZsqaFDh2rChAluKRQAAAAV1SrMJSUlOf7bbDbrwQcf1MyZM91dEwAAAJzk8jVzNpvNnXUAAADABfW6mxUAAAD1y+mVuYceekgmk0lz5sxRUFCQ0zcDNplM+p//+R+XCwQAAEDVTHa73e5MR7PZLJPJpAMHDujqq6+W2ezcop7JZFJpaWmdivQGBQUFCggIUH5+vvz9/T1dDgD8Jk1Y4OkKgJ8tfrJ+x3c2ezi9Mvef//xHktS+fftyrwEAAOA5Toe50NDQal8DAACg4bEBAgAAwMCcXplLT093+UNCQkJcfi8AAACq5nSY69SpU5XPYq2OyWRSSUlJrd8HAACAmjkd5saNG+dSmAMAAED9cTrMvfPOO/VYBgAAAFzBBggAAAADI8wBAAAYGI/zAgAAMDCvfZzXrl27FB8fr6+++krFxcXq0aOHpkyZotGjR9dqnBMnTmju3Ln6/PPPlZGRoaZNm+rqq6/WuHHj9Oijjzo9Do/zAgDP43Fe8CY8zqsaW7ZsUXR0tPz8/DRmzBg1b95cK1euVFxcnDIyMjR16lSnxtm3b5+ioqJ0+vRpjRw5UnfddZcKCwt14MABrV69ulZhDgAAwBs5vTLXUEpKStStWzcdO3ZMX3/9tcLDwyVJ+fn5ioyMVFpamg4fPlzj48QKCgrUo0cPnT9/Xhs3blTPnj0rfI7V6nSWZWUOALwAK3PwJt6yMud1GyA2b96s1NRUjR071hHkJCkgIEAzZszQxYsXtWzZshrHefPNN5Wenq558+ZVCHKSahXkAAAAvFWdE80nn3yid955R3v37lV+fr4CAgLUu3dvjR8/Xr///e9rPV5SUpIkKSoqqsKx6OhoSdLWrVtrHGfFihUymUyKjY3VoUOHtH79ep0/f17dunXTzTffrEaNGtW6NgAAAG/jcpgrKSnR2LFjtXLlStntdlmtVrVq1UrZ2dlatWqVVq9erdjYWC1fvrxWq2ApKSmSpC5dulQ4FhwcrGbNmjn6VOXixYv617/+pdatW+u1115TfHy8bDab43hYWJg+/fRT9ejRo8oxioqKVFRU5HhdUFAgSSouLlZxcbGkS5tCLBaLSktLy41f1l5SUqLLz2JbLBaZzeYq28vGLVP27/bLx6FV1e7j4yObzVZuw4nJZJLVaq2yvaramRNzYk7MyRvnJPEkIniPhvg+OcPlMDd37lx9/PHHGjhwoP72t7+pX79+MpvNstls+uqrr/Tss89q5cqVmjdvnp577jmnx83Pz5d06bRqZfz9/R19qpKXl6fS0lKdOnVKf/nLX/Tiiy/q/vvvV3FxsRYtWqTnn39eo0aN0sGDB+Xn51fl/GbPnl2hff369WrSpIkkKSQkRBEREdq/f7/S09Mdfbp27apu3bpp586dOnnypKM9PDxcoaGh2rZtm86ePeto79evn9q0aaP169eX+8ENGTJEjRs31po1a8rVEBMTo/Pnz2vLli2ONqvVqpEjRyo3N1fJycmO9ubNm2vo0KHKyMjQvn37HO2tW7dW//79lZKSokOHDjnamRNzYk7MyZvnJHHNMrxHfX+fdu/e7VQdLm+ACAsLk5+fn/bv31/pyltxcbF69uypoqIiHTlyxOlxo6KitGHDBqWkpKhz584Vjrdv316FhYXVBrrMzEzHrtsnnnhCCxYsKHc8Li5OCQkJevfdd3XfffdVOkZlK3MdO3ZUbm6u4yJET/+F+mv8q5s5MSfmxJyqm9PEhazMwXsserx+v095eXlq1aqV+25N8ktZWVl6/PHHqzyF6uPjo1GjRum1116r1bhlK3JVhbWCggK1aNHCqTEk6bbbbqtw/LbbblNCQoK+/fbbKsOcr6+vfH19K7T7+PjIx8enXJvFYpHFYqnQt6p/m+r+zerabjabK70HYFXtVdXOnJhTbduZE3OS6n9OgDfx1Pepwuc51asSHTt2VGFhYbV9zp07p5CQkFqNW3atXGXXxWVnZ6uwsLDS6+ku17RpU8fKXGBgYIXjZW2XluwBAACMy+Uw94c//EEJCQnKysqq9Pjx48e1YsUK/eEPf6jVuIMGDZJ06dq0X0pMTCzXpzpDhw6VJP3www8VjpW1derUqVa1AQAAeBunr5m7/MI86dIOjieeeELffPONnnzySQ0YMEBBQUHKycnR9u3btXDhQvXt21cLFiyoVWgqKSlR165ddfz48SpvGnzo0CHHmFlZWcrPz1fbtm3LnV796quvdNNNN+naa6/Vjh07HKtx2dnZuuGGG5SVleV4NJkzuGkwAHgeNw2GN/GWmwbX+tmsv2S326tsL3ufs1try1T1OK+jR49q/vz55R7nNX78eC1btkxLly7V+PHjy40zdepUvfLKK+rYsaNGjRql4uJiffbZZzpx4oTmzJmj6dOnO10TYQ4API8wB2/iLWHO6Q0Q48aNqzS01YchQ4Zox44dio+P14oVK1RcXKwePXrohRdeUFxcnNPjvPzyy+rRo4feeOMNvfPOOzKZTIqIiNA//vEP3XHHHfU4AwAAgIbhdc9m9VaszAGA57EyB2/iLStzXvdsVgAAADiPMAcAAGBgLt80WJLOnj2r119/XRs3blRmZma5JyaUMZlMSk1NrcvHAAAAoAouh7mTJ0+qf//+Sk1Nlb+/v+O87sWLFx03423Xrh138QYAAKhHLp9mnTVrllJTU/W///u/On36tCTpqaee0rlz5/TNN98oMjJSnTp10vfff++2YgEAAFCey2FuzZo1GjZsmO67774Ktyzp06eP1q5dq7S0NM2ePbvORQIAAKByLoe5rKwsRUREOF5bLJZyzzpt0aKFbrnlFiUkJNStQgAAAFTJ5TAXEBCg4uJix+sWLVro2LFj5fr4+/srJyfH9eoAAABQLZfDXFhYmNLS0hyvIyIitGHDBp06dUqSdP78ea1evVohISF1LhIAAACVcznMRUVFadOmTfrpp58kSQ8//LBOnDihXr166e6779Z1112n1NTUCs9LBQAAgPu4HOYeeeQRLV682BHm7rzzTr300ks6d+6cVq5cqezsbE2ZMkXTpk1zW7EAAAAoz+3PZi0tLVVubq7atGlTYZerkfFsVgDwPJ7NCm/iLc9mrdMTICpjsVgUFBTk7mEBAABQiTqHuaysLH344Yfau3ev8vPzFRAQoIiICI0ZM0Zt27Z1R40AAACoQp3C3BtvvKFp06apqKhIl5+tfe+99/Tss89q/vz5euyxx+pcJAAAACrncpj78MMP9cc//lFXXHGFnn32Wf3ud79TUFCQcnJytG3bNi1cuNBxfPTo0e6sGQAAAP/H5Q0QvXv31rFjx7Rv3z61a9euwvFjx44pIiJCISEh2r17d50L9TQ2QACA57EBAt7EWzZAuHxrkgMHDmj06NGVBjlJ6tChg+6++24dOHDA1Y8AAABADVwOc4GBgWratGm1fZo1a6bAwEBXPwIAAAA1cDnM3XbbbVq9erVKSkoqPV5cXKzVq1fr9ttvd7k4AAAAVM/lMPfiiy+qadOmioqK0tdff13uWHJysqKiotS8eXPNmzevzkUCAACgck7vZg0LC6vQdvHiRe3Zs0c33XSTrFarrrjiCuXm5jpW69q2bavevXsrNTXVfRUDAADAwekwZ7PZKjyey8fHRyEhIeXafrkhwmaz1aE8AAAAVMfpMJeWllaPZQAAAMAVLl8zBwAAAM+r87NZJamkpESHDh1SQUGB/P391bVrV1mtbhkaAAAA1ajTylxeXp4mTJiggIAA9ezZUwMGDFDPnj0VGBioiRMn6tSpU+6qEwAAAJVwefksLy9Pffv21Y8//qiWLVvqd7/7ndq2bavs7Gx9++23WrJkibZu3ark5GS1bNnSnTUDAADg/7i8MvfXv/5VP/74o6ZNm6ajR49q3bp1Wrp0qdauXaujR4/qmWeeUUpKiv72t7+5s14AAABcxmS32+2uvDEsLEydOnXS5s2bq+wzdOhQpaWl6ciRIy4X6C2cfdgtAKD+TFjg6QqAny1+sn7HdzZ7uLwyl5mZqX79+lXbp1+/fsrMzHT1IwAAAFADl8NcQECAjh49Wm2fo0ePKiAgwNWPAAAAQA1cDnODBg3SRx99pI0bN1Z6fNOmTfroo480ePBgVz8CAAAANXB5N2t8fLy++OILRUdHKyYmRoMGDVJQUJBycnKUlJSktWvXqkmTJpo5c6Y76wUAAMBlXA5z1157rRITEzV+/Hh98cUX+uKLL2QymVS2n+Kqq67SO++8o2uvvdZtxQIAAKC8Oj2mYcCAAUpJSdGXX36pvXv3Op4AERERoZtuukkmk8lddQIAAKASLoe5hx56SD169NBTTz2lAQMGaMCAAe6sCwAAAE5weQPE8uXLdeLECXfWAgAAgFpyOcxdddVVysrKcmctAAAAqCWXw9xDDz2kL774QsePH3dnPQAAAKgFl6+Zi42N1ZYtW9S/f389/fTT6tOnj4KCgird9BASElKnIgEAAFA5l8NcWFiY41Ykjz/+eJX9TCaTSkpKXP0YAAAAVMPlMDdu3DhuPQIAAOBhLoe5d955x41lAAAAwBUub4AAAACA59XpCRCSVFRUpDVr1mjv3r3Kz89XQECAIiIiFBMTI19fX3fUCAAAgCrUKcytWrVKEydO1MmTJx3PZJUubXpo06aN3nrrLY0aNarORQIAAKByLoe5TZs2KTY2VhaLRQ899JB+97vfKSgoSDk5Odq2bZvee+893XnnnUpMTNTQoUPdWTMAAAD+j8l++ZJaLQwYMED79+/XV199peuuu67C8f379+umm25SeHi4tm/fXudCPa2goEABAQHKz8+Xv7+/p8sBgN+kCQs8XQHws8VP1u/4zmYPlzdA7N27V3FxcZUGOUnq2bOnRo8erT179rj6EQAAAKiBy2GuSZMmat26dbV92rRpoyZNmrj6EQAAAKiBy2Fu+PDh2rhxY7V9Nm7cqBEjRrj6EQAAAKiBy2Fu/vz5OnHihMaNG6eMjIxyxzIyMnT//fcrNzdX8+fPr3ORAAAAqJzLu1nvv/9+tWjRQu+//74+/PBDhYSEOHazpqenq7S0VD179tR9991X7n0mk0mbNm2qc+EAAACoQ5hLSkpy/HdJSYmOHDmiI0eOlOvz3XffVXgfz3MFAABwH5fDnM1mc2cdAAAAcAHPZgUAADAwt4W59PR0bdu2zV3DAQAAwAluC3NLly7VkCFD3DUcAAAAnMBpVgAAAAMjzAEAABgYYQ4AAMDA3BbmAgICFBIS4q7hAAAA4AS3hbknn3xS//nPf9w1nHbt2qWYmBgFBgaqadOm6tu3rxISElwe7/Tp02rfvr1MJpNuvvlmt9UJAADgSS7fNLg+bdmyRdHR0fLz89OYMWPUvHlzrVy5UnFxccrIyNDUqVNrPebkyZOVn59fD9UCAAB4jtNhruwecpGRkfLz86vVPeUGDhzodN+SkhJNmDBBZrNZ27ZtU3h4uCRp5syZioyM1IwZM3TXXXcpNDTU6TFXrlyp5cuX6/XXX9fkyZOdfh8AAIC3czrMDR48WCaTSQcOHNDVV1/teO2M0tJSpwvavHmzUlNT9eCDDzqCnHTpmrwZM2Zo/PjxWrZsmWbOnOnUeCdPntSjjz6q+++/XyNHjiTMAQCAXxWnw9zMmTNlMpl0xRVXlHvtbklJSZKkqKioCseio6MlSVu3bnV6vEceeUQWi0ULFy7kNCsAAPjVcTrMzZo1q9rX7pKSkiJJ6tKlS4VjwcHBatasmaNPTd577z3985//1KeffqoWLVrUKswVFRWpqKjI8bqgoECSVFxcrOLiYkmS2WyWxWJRaWmpbDabo29Ze0lJiex2u6PdYrHIbDZX2V42bhmr9dKPp6SkxKl2Hx8f2Wy2ciuhJpNJVqu1yvaqamdOzIk5MSdvnJPk/kUEwFUN8X1yhtdtgCgLXAEBAZUe9/f3dyqUZWZm6vHHH9c999yj22+/vdZ1zJ07V7Nnz67Qvn79ejVp0kSSFBISooiICO3fv1/p6emOPl27dlW3bt20c+dOnTx50tEeHh6u0NBQbdu2TWfPnnW09+vXT23atNH69evL/eCGDBmixo0ba82aNeVqiImJ0fnz57VlyxZHm9Vq1ciRI5Wbm6vk5GRHe/PmzTV06FBlZGRo3759jvbWrVurf//+SklJ0aFDhxztzIk5MSfm5M1zkvwFeIv6/j7t3r3bqTpM9sv/VKqFs2fP6uTJk+rYsaN8fHwc7StWrNCqVavk5+enSZMmqXfv3rUaNyoqShs2bFBKSoo6d+5c4Xj79u1VWFhYY6CLiYnR7t279f333ztODaelpenKK69UdHS01q1bV+37K1uZ69ixo3Jzc+Xvf+mXiaf/Qv01/tXNnJgTc2JO1c1p4kJW5uA9Fj1ev9+nvLw8tWrVSvn5+Y7sURmXV+aefvppvffee8rJyXGEub///e+aPHmy4wv74Ycfavfu3erWrZvT45atyFUV1goKCtSiRYtqx1i2bJnWrl2rjz76yBHkasvX11e+vr4V2n18fMqFV+nSLyWLxVKh78+nBZxr/+W4rrSbzWaZzRVvH1hVe1W1MyfmVNt25sScpPqfE+BNPPV9qvB5TvWqxNatWzV8+HDHKUdJmjdvntq3b69t27YpISFBdrtdL730Uq3GLbtWrrLr4rKzs1VYWFjp9XSX27t3ryTp7rvvlslkcvzvyiuvlCQlJibKZDKV2y0LAABgRC6vzGVlZZV7ksKBAweUkZGhF198UQMGDJAkffzxx7W6H50kDRo0SHPnztX69es1ZsyYcscSExMdfarTr18/FRYWVmgvLCzUihUr1KFDB0VHR/P4MQAAYHguh7mioiI1atTI8Xrr1q0ymUzlbikSFhamVatW1WrcYcOGKSwsTMuXL9fjjz/uWD3Lz8/XnDlz1KhRI40bN87RPysrS/n5+Wrbtq3jFG1cXJzi4uIqjJ2WlqYVK1bo2muv1ZIlS2pVFwAAgDdy+TRrhw4dtH//fsfrzz//XC1btlTPnj0dbadOnVKzZs1qNa7VatWSJUtks9k0cOBATZw4UVOnTlWvXr10+PBhzZkzR506dXL0nz59uq655hp98sknrk4FAADAsFxembvlllv0xhtv6E9/+pP8/Py0bt26citmknT48GGXTmUOGTJEO3bsUHx8vFasWKHi4mL16NFDL7zwQqUrbgAAAL9VLt+aJDs7W/3791daWpokqW3btvrmm2/UoUMHSdKJEyfUoUMHTZ48Wa+88orbCvaUgoICBQQE1Lg9GABQfyYs8HQFwM8WP1m/4zubPVxemQsODtb333+vTZs2SZIGDhxY7oNyc3P10ksvOR7BBQAAAPer0xMgGjdurFtvvbXSY927d1f37t3rMjwAAABq4PIGCAAAAHhenVbmSktLlZCQoI0bNyozM7Pc46/KmEwmx6lYAAAAuJfLYe7cuXOKiorS119/LbvdLpPJVO65e2WvTSaeowcAAFBfXD7N+vzzzys5OVmzZ89Wbm6u7Ha7Zs2apaysLK1YsUJhYWG6++67K12tAwAAgHu4HOb++c9/qm/fvnruuefUsmVLR3tQUJDuvvtubdmyRRs3bqz1s1kBAADgPJfDXHp6uvr27fvzQGZzuVW4Dh06aOTIkVq2bFndKgQAAECVXA5zTZs2ldn889sDAgKUlZVVrk9wcLDS09Ndrw4AAADVcjnMhYaGlgtq1113nTZv3uxYnbPb7dq0aZPatm1b9yoBAABQKZfD3LBhw7RlyxaVlJRIkh544AGlp6erX79+mjZtmgYMGKB9+/YpNjbWbcUCAACgPJdvTTJhwgS1atVKJ0+eVNu2bfXQQw9p7969evPNN7Vv3z5JUmxsrGbNmuWmUgEAAPBLJvvlN4dzg5MnT+rIkSMKDQ1VcHCwO4f2KGcfdgsAqD8TFni6AuBni5+s3/GdzR51egJEZVq3bq3WrVu7e1gAAABUgmezAgAAGJjLK3NhYWFO9TOZTEpNTXX1YwAAAFANl8OczWar9Lmr+fn5OnPmjCSpbdu2atSokcvFAQAAoHouh7m0tLRqj02ZMkU5OTnasGGDqx8BAACAGtTLNXOdOnXSihUrdPr0aT377LP18REAAABQPW6A8PHx0YgRI5SQkFBfHwEAAPCbV6+7WX/66Sfl5eXV50cAAAD8ptVbmNu+fbs++OADde3atb4+AgAA4DfP5Q0QQ4cOrbS9pKREx48fd2yQmDlzpqsfAQAAgBq4HOaSkpIqbTeZTGrRooWioqI0ZcoUjRgxwtWPAAAAQA3qdJ85AAAAeFadn8164sQJHT9+XDabTe3bt1dwcLA76gIAAIATXNoAUVRUpBdffFFdunRR27ZtdcMNNygyMlLt27fXFVdcoaeeeqramwoDAADAPWod5jIyMtSnTx9Nnz5dqampatu2rSIjIxUZGam2bdsqLy9PCxcu1A033KCNGzc63peVlcU95wAAANysVmGuuLhYMTEx+ve//6177rlHBw4c0LFjx5ScnKzk5GQdO3ZMBw4c0L333qu8vDz9/ve/V1pamlJTUzVgwAAdPHiwvuYBAADwm1Sra+YWLVqk77//XvHx8YqPj6+0T9euXfXuu+/q6quvVnx8vO69916lpaUpNzdX119/vVuKBgAAwCW1WplLSEhQ586dnbp33HPPPacuXbooOTlZFy5cUGJiokaOHOlyoQAAAKioVmHuhx9+UFRUlEwmU419TSaTo+8333yjwYMHu1ojAAAAqlCrMFdYWKiAgACn+/v7+8tqtapz5861LgwAAAA1q1WYa9OmjX788Uen+6empqpNmza1LgoAAADOqVWY69evn9auXavs7Owa+2ZnZ+uLL77QgAEDXC4OAAAA1atVmHvkkUdUWFioO+64Q7m5uVX2O3XqlO644w799NNPevjhh+tcJAAAACpXq1uTDBkyRBMmTNDixYt1zTXX6OGHH9bQoUPVsWNHSZduKLxp0yYtXrxYubm5mjhxIhsfAAAA6lGtn8365ptvyt/fX6+++qrmzp2ruXPnljtut9tlNpv1pz/9qcIxAAAAuFetw5zFYtFLL72kiRMn6p133lFycrLjGrrg4GD1799fDzzwgLp06eL2YgEAAFBercNcmS5duuhvf/ubO2sBAABALdVqAwQAAAC8C2EOAADAwAhzAAAABkaYAwAAMDDCHAAAgIER5gAAAAyMMAcAAGBghDkAAAADI8wBAAAYGGEOAADAwAhzAAAABkaYAwAAMDDCHAAAgIER5gAAAAyMMAcAAGBghDkAAAADI8wBAAAYGGEOAADAwAhzAAAABkaYAwAAMDDCHAAAgIER5gAAAAyMMAcAAGBgXhvmdu3apZiYGAUGBqpp06bq27evEhISnHqv3W7X2rVr9eijj6pnz54KCAhQkyZN1KtXL82ZM0cXLlyo5+oBAAAahtXTBVRmy5Ytio6Olp+fn8aMGaPmzZtr5cqViouLU0ZGhqZOnVrt+4uKihQTEyNfX18NHjxY0dHRunDhghITE/Xss8/q008/VVJSkpo0adJAMwIAAKgfJrvdbvd0EZcrKSlRt27ddOzYMX399dcKDw+XJOXn5ysyMlJpaWk6fPiwQkNDqxyjuLhYL774oh577DG1aNGiXHtsbKxWr16tF198UdOmTXO6roKCAgUEBCg/P1/+/v4uzw8A4LoJCzxdAfCzxU/W7/jOZg+vO826efNmpaamauzYsY4gJ0kBAQGaMWOGLl68qGXLllU7ho+Pj5599tlyQa6sffr06ZKkrVu3ur12AACAhuZ1YS4pKUmSFBUVVeFYdHS0pLoFMR8fH0mS1eqVZ5gBAABqxesSTUpKiiSpS5cuFY4FBwerWbNmjj6uePvttyVVHhYvV1RUpKKiIsfrgoICSZdO1RYXF0uSzGazLBaLSktLZbPZHH3L2ktKSnT5WWyLxSKz2Vxle9m4ZcoCZ0lJiVPtPj4+stlsKi0tdbSZTCZZrdYq26uqnTkxJ+bEnLxxTpJJgLdoiO+TM7wuzOXn50u6dFq1Mv7+/o4+tbV27VotWrRI11xzjf7rv/6r2r5z587V7NmzK7SvX7/esXEiJCREERER2r9/v9LT0x19unbtqm7dumnnzp06efKkoz08PFyhoaHatm2bzp4962jv16+f2rRpo/Xr15f7wQ0ZMkSNGzfWmjVrytUQExOj8+fPa8uWLY42q9WqkSNHKjc3V8nJyY725s2ba+jQocrIyNC+ffsc7a1bt1b//v2VkpKiQ4cOOdqZE3NiTszJm+ckcc0yvEd9f592797tVB1etwEiKipKGzZsUEpKijp37lzhePv27VVYWFjrQLdr1y4NGzZMVqtV27dv17XXXltt/8pW5jp27Kjc3FzHRYie/gv11/hXN3NiTsyJOVU3p4kLWZmD91j0eP1+n/Ly8tSqVasaN0B43cpc2YpcVWGtoKCgwsaGmnz77beKioqS2WxWYmJijUFOknx9feXr61uh3cfHx3HdXRmLxSKLxVKhb1XX5VXV/stxXWk3m80ymyteCllVe1W1MyfmVNt25sScpPqfE+BNPPV9qvB5TvVqQGXXylV2XVx2drYKCwsrvZ6uKt9++61GjBghm82mxMRE9enTx221AgAAeJrXhblBgwZJunRt2i8lJiaW61OTsiBXWlqqdevW6cYbb3RfoQAAAF7A68LcsGHDFBYWpuXLl5e7eDA/P19z5sxRo0aNNG7cOEd7VlaWDh48WOG07O7duzVixAiVlJRo7dq16tevX0NNAQAAoMF43TVzVqtVS5YsUXR0tAYOHFjucV5Hjx7V/Pnz1alTJ0f/6dOna9myZVq6dKnGjx8vScrLy9OIESN05swZ3XzzzdqwYYM2bNhQ7nMCAwP15JNPNtzEAAAA6oHXhTnp0tb0HTt2KD4+XitWrFBxcbF69OihF154QXFxcTW+v6CgQKdPn5YkrVu3TuvWravQJzQ0lDAHAAAMz+tuTeKteDYrAHgez2aFN+HZrAAAAKgzwhwAAICBEeYAAAAMjDAHAABgYIQ5AAAAAyPMAQAAGBhhDgAAwMAIcwAAAAZGmAMAADAwwhwAAICBEeYAAAAMjDAHAABgYIQ5AAAAAyPMAQAAGBhhDgAAwMAIczCkN954Q506dZKfn59uvPFG7dy5s8q+33//vWJjY9WpUyeZTCYtWLCg4QoFAKCeEeZgOCtWrNCUKVMUHx+vPXv2qFevXoqOjtaJEycq7f/TTz8pLCxM8+bNU3BwcANXCwBA/SLMwXBeeeUVTZgwQQ8++KC6d++uf/zjH2rSpInefvvtSvv36dNHL730ksaMGSNfX98GrhYAgPpFmIOhXLx4Ubt379bw4cMdbWazWcOHD1dycrIHKwMAwDMIczCU3NxclZaWKigoqFx7UFCQsrOzPVQVAACeQ5gDAAAwMMIcDOWKK66QxWJRTk5OufacnBw2NwAAfpMIczCURo0a6frrr9emTZscbTabTZs2bVK/fv08WBkAAJ5h9XQBQG1NmTJFDzzwgG644QZFRkZqwYIFOnfunB588EFJ0rhx49S+fXvNnTtX0qVNEz/88IPjv48fP659+/apWbNm6ty5s8fmAQCAOxDmYDhxcXE6efKkZs6cqezsbIWHh2vdunWOTRHp6ekym39edM7MzFRERITj9fz58zV//nwNGjRISUlJDV0+AABuZbLb7XZPF2EEBQUFCggIUH5+vvz9/T1dDgD8Jk1Y4OkKgJ8tfrJ+x3c2e3DNHAAAgIER5gAAAAyMMAcAAGBgbIDwMlwPAm9S39eDAADqjpU5AAAAAyPMAQAAGBhhDgAAwMAIcwAAAAZGmAMAADAwwhwAAICBEeYAAAAMjDAHAABgYIQ5AAAAAyPMAQAAGBhhDgAAwMAIcwAAAAZGmAMAADAwwhwAAICBEeYAAAAMjDAHAABgYIQ5AAAAAyPMAQAAGBhhDgAAwMAIcwAAAAZGmAMAADAwwhwAAICBEeYAAAAMjDAHAABgYIQ5AAAAAyPMAQAAGBhhDgAAwMAIcwAAAAZGmAMAADAwwhwAAICBEeYAAAAMjDAHAABgYF4b5nbt2qWYmBgFBgaqadOm6tu3rxISEmo1RlFRkf7yl7+oS5cu8vPzU7t27TRx4kSdOHGinqoGAABoWFZPF1CZLVu2KDo6Wn5+fhozZoyaN2+ulStXKi4uThkZGZo6dWqNY9hsNt1+++1KTExU3759FRsbq5SUFC1ZskSbNm3S119/rdatWzfAbAAAAOqP163MlZSUaMKECTKbzdq2bZveeustvfzyy/ruu+909dVXa8aMGTp69GiN4yxbtkyJiYm655579NVXX2nevHlauXKl3nzzTR05ckTPPfdcA8wGAACgfnldmNu8ebNSU1M1duxYhYeHO9oDAgI0Y8YMXbx4UcuWLatxnMWLF0uS5s6dK5PJ5Gh/+OGHFRYWpvfff1/nz593e/0AAAANyevCXFJSkiQpKiqqwrHo6GhJ0tatW6sd48KFC/rmm2/UtWtXhYaGljtmMpk0YsQInTt3Tt9++617igYAAPAQrwtzKSkpkqQuXbpUOBYcHKxmzZo5+lQlNTVVNput0jEuH7umcQAAALyd122AyM/Pl3TptGpl/P39HX3qMsbl/SpTVFSkoqKiCmPm5eWpuLhYkmQ2m2WxWFRaWiqbzeboW9ZeUlIiu93uaLdYLDKbzVW2FxcX6+IFn2rnBjSkU6eKy722Wi/9yigpKSnX7uPjI5vNptLSUkebyWSS1Wqtsr2q7407v0/O1M6cjDWnixdMArzFmTP1+33Ky8uTpHLfncp4XZjzFnPnztXs2bMrtF955ZUeqAbwjP+d7ukKAMB7NdTvyLNnz1a5QCV5YZgrK7aqVbOCggK1aNGizmNc3q8y06dP15QpUxyvbTab8vLy1KpVq3IbKuB9CgoK1LFjR2VkZDhWYQEAl/A70jjsdrvOnj2rdu3aVdvP68Lc5dezXX/99eWOZWdnq7CwUJGRkdWOERYWJrPZXOU1cdVdl1fG19dXvr6+5doCAwNrKh9exN/fn19UAFAFfkcaQ3ULT2W8bgPEoEGDJEnr16+vcCwxMbFcn6o0btxYkZGROnToUIV70tntdm3YsEFNmzbVDTfc4KaqAQAAPMPrwtywYcMUFham5cuXa9++fY72/Px8zZkzR40aNdK4ceMc7VlZWTp48GCFU6oTJ06UdOl06eUXDi5atEhHjhzRvffeq8aNG9fvZAAAAOqZ14U5q9WqJUuWyGazaeDAgZo4caKmTp2qXr166fDhw5ozZ446derk6D99+nRdc801+uSTT8qN88ADDyg6OloffPCB+vfvrz//+c+666679Nhjj+nKK6/U888/38AzQ0Px9fVVfHx8hdPkAAB+R/4amew17Xf1kJ07dyo+Pl5fffWViouL1aNHD02ZMkVxcXHl+o0fP17Lli3T0qVLNX78+HLHioqKNG/ePL377rvKyMhQy5Ytdeutt+r5559XUFBQA84GAACgfnhtmAMAAEDNvO40KwAAAJxHmAMAADAwwhwAAICBEeYAAAAMjDAHAABgYIQ5AAAAAyPMAQAAGBhhDoZns9k8XQIAAB5DmIPhmc0//9+YYAcAFZWWlnq6BNQjwhwMKycnR1OnTlViYqLOnDkj6edgZ7fbCXYAfvPKfg9aLBZJzv9u5OFQxsLjvGBY8fHx+utf/6pOnTqpe/fuGjx4sAYNGqSePXuWe4C0zWaT3W6XxWJRUlKSLly4oJtvvtmDlQNAw/j73/+upKQkjRs3ToMGDVKzZs0cx8pC3eVnN2BMhDkYVkREhH744Qf17t1be/bsUXFxsUJDQ3XTTTdpyJAhuummm9StWzdH/59++kn33HOPPv/8c507d05+fn4erB4A6t+VV16po0ePytfXV7169VJUVJRiYmJ04403ymQyOfqVlJTIarXqp59+0ltvvaVevXppyJAhHqwctUGYgyFlZGRo4MCBatWqlZKTk7V7926tWbNGq1at0v79+2U2m3Xttddq4MCBGjhwoKKjo3Xo0CHddttt6tOnj1atWuXpKQBAvfr+++/Vo0cPXX/99WrRooU2btwoSWratKluuukmxcTEKCoqqtwfvTt27NDAgQPVv39/7dixw1Olo5asni4AcEVWVpYKCgo0aNAg+fj4qE+fPoqMjNTkyZO1Z88effbZZ1q7dq3eeOMNvf3227rhhhvk4+OjnJwcTZw40dPlA0C9+9e//iVJGjt2rJ566ikdPnxYn376qT744AOtX79e69evV3BwsAYPHqxbbrlFt956q3bu3ClJmj59uidLRy2xMgdD+vHHH/XMM88oNjZWY8eOrXC8uLhYmZmZ2r59u1avXq2NGzfq9OnTCgwMVF5engcqBoCG9dZbb+mRRx7RF198oVtuuaXcsV27dumDDz7Qxx9/rGPHjkmSunTpooKCAp0/f96xqQzGQJiDYeXn56ukpEStWrWqso/NZpPZbNaiRYv06KOP6tFHH9Ubb7zRgFUCQMOz2+365ptvlJCQoEmTJumqq65ytF9+rdyFCxe0adMmffTRR/r0009VUFCgSZMm6bXXXvNU6XABYQ6G88tfRtKleyiZTKYqd2U9/fTTmj9/vr799lv17t27IcoEAI8rLCxUo0aN1KhRowrHfvm7dPLkyXrzzTe1Z88ehYeHN2CVqCvCHAyp7JdQdna22rRpUy7ElZaWymw2O35JHTt2TCNHjlRmZqZOnjzpqZIBwOuU/S5NTU1VXFyc8vPzlZKS4umyUEtsgIChlJSU6Msvv9Tbb7+tw4cPy2w2q3HjxurVq5diY2PVv39/x80xy/j5+Wn8+PFq166dh6oGAO9U9kfvgQMHtGfPHk2bNs3DFcEVrMzBUObPn6+//vWvOnv2rDp37iyLxaJDhw45jnfr1k0TJkzQPffco+DgYEf7xYsXZbVauTkmgN+Uyi5LqUxOTo7WrVunUaNGqWXLlg1QGdyJMAfD+M9//qMePXqod+/eWrZsmRo1aqSgoCBlZ2dr9erV+uijj5SUlCRJGjp0qF588UWujwPwm3L+/Hmlp6crJCREjRs3rtV7S0tLK5zZgDEQ5mAYM2fO1KJFi7R8+XINGzZMUsW/Ov/1r39p/vz5SkhIUGhoqN5//31df/31Tv91CgBGNm/ePK1cuVJ33nmn+vbtq65duyooKKjakHby5Em1aNFCVitXXhkVYQ6GERsbq3379mnLli0KCQlxPH6m7MHRl/+yWrhwoZ566ik98MADWrp0qQerBoCG06FDB2VmZspisSggIED9+/dXVFSUbrzxRoWFhVW4ldO5c+c0a9YsnTp1SosXL2ZlzqCI4TCMiIgIffLJJyosLJQkx1+RJpPJ8QuobAXuiSee0Pbt27V582YdOXJEYWFhHqsbABrC4cOHlZ+fr379+mns2LHasGGDkpOT9fnnnyskJESDBw/W8OHDFRERofbt2yswMFD//ve/tXjxYg0ePJggZ2CEORhG2UOf7733Xr388ssaMGBApfdOKrvuo2vXrlq7dq0j/AHAr9nhw4d14cIFRUVFadKkSbr11lt16NAhJScna/PmzVq5cqXef/99de/eXUOHDtXNN9+sTZs2qaCgQBMmTPB0+agDTrPCMEpLS/XMM8/olVdeUbdu3TRp0iTdddddCgoKqtD39OnTevLJJ7V27VqdOHHCA9UCQMP6+OOPNXr0aH344YcaPXq0o724uFhHjx7Vd999p+3btyspKUkHDhyQj4+P7Ha7fH19ecyhwRHmYDiLFi3SSy+9pCNHjqhdu3a64447dMstt6hjx46yWCwKDAzUa6+9pgULFuixxx7Tyy+/7OmSAaDe2e12HTx4UH5+frryyisr3fh17tw5HT58WIcOHdLSpUu1YcMGTZ48Wf/93//toarhDoQ5GI7dbtePP/6oxYsX68MPP3Q8JLpNmzby8fFRVlaWbDab7rnnHr3wwgvq0KGDhysGAM+qLNg9/vjjev3117V7925FRER4qDK4A2EOhnbu3Dnt3LlTq1atUmZmpk6cOCF/f3+NHj1asbGx8vPz83SJAOA1bDabzGaz0tLSdPvtt+v06dNKT0/3dFmoIzZAwNCaNm2qIUOGaMiQISouLpaPj4+nSwIAr1X2FJzjx4+ruLhYjz32mIcrgjuwMgcAwG+M3W7XsWPH1LJlSzVt2tTT5aCOCHMAAAAGxlPHAQAADIwwBwAAYGCEOQAAAAMjzAEAABgYYQ4AAMDACHMAAAAGRpgDAAAwMMIcAACAgRHmAAAADOz/Aze6Cl884AlHAAAAAElFTkSuQmCC" + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Sampling\n", + "qb_2n.threshold = 0.97\n", + "samples = qb_2n.rejection_sampling(evidence=evidence)\n", + "plot_histogram(samples)" + ] + }, + { + "cell_type": "markdown", + "id": "5bf133a4bdd8a976", + "metadata": { + "collapsed": false + }, + "source": [ + "We can also print the result in a better format to understand which values belong to which variables:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "4f019762e7f6b861", + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-03-15T12:25:44.619555Z", + "start_time": "2024-03-15T12:25:44.540091Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'P(Y=0|X=1)': 0.1004712084149367, 'P(Y=1|X=1)': 0.8995287915850584}\n" + ] + } + ], + "source": [ + "qb_2n.threshold = 0.97\n", + "samples = qb_2n.rejection_sampling(evidence=evidence, format_res=True)\n", + "print(samples)" + ] + }, + { + "cell_type": "markdown", + "id": "9f6ab51740b00957", + "metadata": { + "collapsed": false + }, + "source": [ + "#### 3.1.2. Burglary Alarm Example\n", + "For the advanced example, we can follow the steps from above in the same way. However, we look at the trivial case of how to obtain the joint probability of the network. This can be calculated by providing no evidence for the rejection sampling method. (For optical reasons, we only plot probabilities that are greater than 0.01%.)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "8d4904619b35503a", + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-03-15T12:25:44.729578Z", + "start_time": "2024-03-15T12:25:44.618613Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": "
", + "image/png": "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bGyytVtZWcHKysqozcLCIsei0PACyG/74/stTLtOp4NOl/3DILf23LKzT+xTQdvZp6LrU3Ew9I+/J/YJYJ9yy1jQ9pLyHlHiLoAwnCuX03lxMTExSE5OzvF8uqzu3buHo0ePolatWmohl1Xr1q0BAOfOnSuCxERERETmU+KKuZYtWwJ4dH7H43bv3m20TW7S0tIA5D71iOGYek4jb0RERERaUuKKubZt28LT0xNr1641OnkwMTERM2fOhLW1NQYMGKC2R0dH48qVK0aHZcuWLYuaNWsiIiICK1asMNr/3bt3MW/ePAD/jNARERERaVWJK+YsLS2xYsUK6PV6tGjRAkOHDsXYsWNRr149XLt2DTNnzkTVqlXV7SdNmoRatWph8+bNRvv54osvYGlpiSFDhqBdu3YYN24c3nrrLdSoUQNXrlxBjx490K5dOxP3joiIiKholbgLIIBHI2ZHjhzBtGnTsH79eqSnp6Nu3br4/PPPERAQkK99vPzyyzh27Bjmzp2LI0eO4NChQ7C1tUWtWrUwdepUvP3228XcCyIiIqLiV+KmJimpuDYrEZkC12YlIgPNrs1KRERERPnHYo6IiIhIw1jMEREREWkYizkiIiIiDWMxR0RERKRhLOaIiIiINIzFHBEREZGGsZgjIiIi0jAWc0REREQaxmKOiIiISMNYzBERERFpGIs5IiIiIg1jMUdERESkYSzmiIiIiDSMxRwRERGRhrGYIyIiItIwFnNEREREGsZijoiIiEjDWMwRERERaRiLOSIiIiINYzFHREREpGEs5oiIiIg0jMUcERERkYaxmCMiIiLSMBZzRERERBrGYo6IiIhIw1jMEREREWkYizkiIiIiDWMxR0RERKRhLOaIiIiINIzFHBEREZGGsZgjIiIi0jAWc0REREQaxmKOiIiISMNYzBERERFpGIs5IiIiIg1jMUdERESkYSzmiIiIiDSMxRwRERGRhrGYIyIiItIwFnNEREREGsZijoiIiEjDWMwRERERaRiLOSIiIiINYzFHREREpGEs5oiIiIg0jMUcERERkYaxmCMiIiLSsEIXc7Vr18YXX3yB27dvF2UeIiIiIiqAQhdzERER+OCDD/DMM8+gb9++2L9/f1HmIiIiIqJ8KHQxFxMTgyVLlqBOnTpYv3492rdvj+rVq2P27NmIiYkpyoxERERElItCF3OlS5fGsGHDcOrUKZw/fx4jRozAnTt3MHnyZFSuXBmvvvoqdu7cCREpyrxERERElEWRXABRt25dfPXVV7h58yZ+/PFHNG/eHL/++is6d+6MKlWqYMaMGYiKiiqKhyIiIiKiLIr0alYbGxv4+/ujY8eOcHd3h4jgxo0bmDFjBjw9PfHOO+/g/v37RfmQRERERP9pRVbMBQYGonfv3njmmWcwYcIEKIqCKVOm4K+//sKGDRvw/PPPY+nSpXjnnXeK6iGJiIiI/vMsn+bOUVFR+O677/D999/j+vXrAIAOHTpg2LBh6NKlCywsLAAAnp6e6NmzJ7p06YJff/316VMTEREREYCnKOY6d+6M3bt3IzMzE25ubpgwYQKGDh2KqlWr5nqfZs2aYceOHYV9SCIiIiJ6TKGLuR07dqBNmzYYNmwYXnnlFVhaPnlXXbp0QYUKFQr7kERERET0mEIXc9euXUP16tULdJ86deqgTp06hX1IIiIiInpMoS+AmDlzJn777bc8t9m2bRveeOONwj4EERERET1BoYu5lStXIjg4OM9tzp8/j1WrVhX2IYiIiIjoCYp0nrnHPXz4MF/n0hERERFR4TxVpaUoSo7tIoLIyEjs3LmTFzwQERERFaMCjczpdDpYWFio88dNnz5d/TnrP0tLS1SrVg1nz55Fnz59iiU4ERERERVwZK5FixbqaNzhw4dRuXLlHOeVs7CwgIuLC9q0aYMhQ4YUSVAiIiIiyq5AxdzBgwfV/9fpdBg8eDCmTp1a1JmIiIiIKJ8Kfc6cXq8vyhxEREREVAjFejXr0zh16hQ6duyIMmXKwN7eHk2aNMGGDRsKvJ9bt25h9OjR8PLygq2tLcqWLYumTZvim2++KYbURERERKaV75G5N954A4qiYObMmXBzc8v3ZMCKouB///tfgUIdOHAA/v7+sLW1RZ8+feDg4ICff/4ZAQEBiIyMxNixY/O1n+DgYHTo0AF37txBp06d0LNnTyQnJ+Py5cvYunUr3n777QLlIiIiIippFBGR/Gyo0+mgKAouX76MGjVqQKfL36CeoijIzMzMd6CMjAx4e3vjxo0bOH78OHx9fQEAiYmJ8PPzQ3h4OK5du4YqVarkuZ+kpCTUrVsXDx48wN69e+Hj45PtcQoyB15SUhKcnJyQmJgIR0fHfN+PiKgghiwsnv0uH1U8+yWi4pPf2iPf1czff/8NAKhYsaLRz0Vt//79CA0NxeDBg9VCDgCcnJwwefJkDBo0CKtWrXrihRdLlixBREQE/ve//2Ur5ABwMmMiIiL6V8h3RfP4SNiTRsYKy3DFbIcOHbLd5u/vDwA4dOjQE/ezfv16KIqCHj164OrVqwgMDMSDBw/g7e2Nl156CdbW1kWam4iIiMgcStzwVEhICADAy8sr223u7u4oXbq0uk1u0tLScPHiRbi6uuKrr77CtGnTjK6+9fT0xJYtW1C3bt1c95GamorU1FT156SkJABAeno60tPTAfwziXJmZqbR/g3tGRkZyHoU28LCAjqdLtd2w34NDKOHGRkZ+Wq3srKCXq83OqytKAosLS1zbc8tO/vEPrFP5ulTcV2Xlp6ezt8T+8Q+abBP+ZHvYi4iIiK/m2ZTuXLlfG+bmJgI4NFh1Zw4Ojqq2+QmISEBmZmZuH37Nj7++GPMmTMH/fv3R3p6OpYtW4ZPP/0UXbp0wZUrV2Bra5vjPmbNmoUZM2Zkaw8MDISdnZ3ar/r16+PChQtGz0/NmjXh7e2NkydPIi4uTm339fVFlSpVcPjwYdy7d09tb9q0KcqXL4/AwECjX1zr1q1RqlQp7NixwyhDx44d8eDBAxw4cEBts7S0RKdOnRAfH4+goCC13cHBAW3atEFkZCSCg4PVdldXVzRr1gwhISG4evWq2s4+sU/sk3n7BBTPUY/AwED+ntgn9kljfTpz5gzyo8AXQBSUoij5riyBR4dX9+zZg5CQEFSvXj3b7RUrVkRycnKeBd3NmzfVc/vef/99LFy40Oj2gIAAbNiwAT/++CP69euX4z5yGpmrVKkS4uPj1ZMQ/6vfEtgn9ol9Kr4+DfuyeEbmlrzDkTn2iX3SWp8SEhJQtmzZorsAYsCAAYUq5grKMCKXW7GWlJQEZ2fnfO0DALp27Zrt9q5du2LDhg04ffp0rsWcjY0NbGxssrVbWVnBysrKqC3rerVZ5XaRRW7tj++3MO06nS7HK41za88tO/vEPhW0nX0quj4VB0P/+HtinwD2KbeMBW0vKe8R+X4nWblyZX43fSqGc+VCQkLQoEEDo9tiYmKQnJwMPz+/PPdhb2+PihUrIioqCmXKlMl2u6HtwYMHRZKZiIiIyFxK3AoQLVu2BPDo/I7H7d6922ibvLRp0wYA8Oeff2a7zdBWtWrVwsYkIiIiKhFKXDHXtm1beHp6Yu3atUYnDyYmJmLmzJmwtrbGgAED1Pbo6GhcuXIl22HZ4cOHAwBmz56Nu3fvqu0xMTFYtGgRdDodevToUax9ISIiIipuJW45L0tLS6xYsQL+/v5o0aKF0XJe169fx7x584xG1CZNmoRVq1bh+++/x6BBg9T2Zs2aYcyYMViwYAF8fHzQpUsXpKen49dff8WtW7cwc+ZM1KhRI9+5iIiIiEqiAp0zpygKJkyYADc3t3yfQ1eYtVlbt26NI0eOYNq0aVi/fj3S09NRt25dfP755wgICMj3fubPn4+6deti8eLFav769etj6dKleOWVVwqUiYiIiKgkyvfUJNevXwfwaGoQS0tL9ef8KK7VIkyJa7MSkSlwbVYiMijytVlNtZwXEREREeVfibsAgoiIiIjy76mLuc2bN6Nbt26oXLkynJycULlyZXTv3h1btmwpgnhERERElJdCTz+ekZGB1157DT///DNEBJaWlihbtixiYmLw22+/YevWrejRowfWrl1r0lnOiYiIiP5LCj0yN2vWLGzatAkvvvgifv/9dzx8+BDR0dF4+PAhDh8+jObNm+Pnn3/G7NmzizIvEREREWWR76tZH+fp6QlbW1tcuHAhx5G39PR0+Pj4IDU1FWFhYU8d1Nx4NSsRmQKvZiUig/zWHoUemYuOjkaXLl3yXMC2S5cuiI6OLuxDEBEREdETFLqYq1SpEpKTk/PcJiUlBZUrVy7sQxARERHRExS6mHvrrbewYcOGXEfeoqKisH79erz11luFDkdEREREecv3ZaYRERFGP/fu3RtHjx5F/fr1MWrUKDRv3hxubm6IjY3F77//jkWLFqF58+bo1atXkYcmIiIiokfyfQGETqeDoijZ2kUk13bD/TIyMp4ypvnxAggiMgVeAEFEBkW+nNeAAQNyLNqIiIiIyHzyXcytXLmyGGMQERERUWFwbVYiIiIiDWMxR0RERKRhT7Vo6r179/D1119j7969uHnzJlJTU7NtoygKQkNDn+ZhiIiIiCgXhS7m4uLi0KxZM4SGhsLR0VG94iItLQ0PHjwAAFSoUAFWVlZFFpaIiIiIjBX6MOv06dMRGhqKH374AXfu3AEAjB49GikpKThx4gT8/PxQtWpV/PHHH0UWloiIiIiMFbqY27FjB9q2bYt+/fplm7KkUaNG2LlzJ8LDwzFjxoynDklEREREOSt0MRcdHY369eurP1tYWKiHVwHA2dkZL7/8MjZs2PB0CYmIiIgoV4Uu5pycnJCenq7+7OzsjBs3bhht4+joiNjY2MKnIyIiIqI8FbqY8/T0RHh4uPpz/fr1sWfPHty+fRsA8ODBA2zduhWVK1d+6pBERERElLNCF3MdOnTAvn37cP/+fQDAsGHDcOvWLdSrVw+9evVCnTp1EBoaikGDBhVVViIiIiJ6TKGLueHDh2P58uVqMffqq69i7ty5SElJwc8//4yYmBiMGTMG48aNK7KwRERERGRMEREpyh1mZmYiPj4e5cuXz3aVq5YZ5tFLTEyEo6OjueMQ0b/UkIXFs9/lo4pnv0RUfPJbezzVChA5sbCwgJubW1HvloiIiIhy8NTFXHR0NNatW4dz584hMTERTk5OqF+/Pvr06QMPD4+iyEhEREREuXiqYm7x4sUYN24cUlNTkfVo7erVq/Hhhx9i3rx5GDFixFOHJCIiIqKcFbqYW7duHd59912UK1cOH374IV588UW4ubkhNjYWhw8fxqJFi9Tbe/fuXZSZiYiIiOj/FfoCiOeffx43btxAcHAwKlSokO32GzduoH79+qhcuTLOnDnz1EHNjRdAEJEp8AIIIjLIb+1R6KlJLl++jN69e+dYyAHAM888g169euHy5cuFfQgiIiIieoJCF3NlypSBvb19ntuULl0aZcqUKexDEBEREdETFLqY69q1K7Zu3YqMjIwcb09PT8fWrVvRrVu3QocjIiIiorwVupibM2cO7O3t0aFDBxw/ftzotqCgIHTo0AEODg6YPXv2U4ckIiIiopzl+2pWT0/PbG1paWk4e/YsXnjhBVhaWqJcuXKIj49XR+s8PDzw/PPPIzQ0tOgSExEREZEq38WcXq/PtjyXlZUVKleubNT2+AURer3+KeIRERERUV7yXcyFh4cXYwwiIiIiKoxCnzNHREREROb31GuzAkBGRgauXr2KpKQkODo6ombNmrC0LJJdExEREVEenmpkLiEhAUOGDIGTkxN8fHzQvHlz+Pj4oEyZMhg6dChu375dVDmJiIiIKAeFHj5LSEhAkyZN8Ndff8HFxQUvvvgiPDw8EBMTg9OnT2PFihU4dOgQgoKC4OLiUpSZiYiIiOj/FXpk7pNPPsFff/2FcePG4fr169i1axe+//577Ny5E9evX8eECRMQEhKCzz77rCjzEhEREVEWiohIYe7o6emJqlWrYv/+/blu06ZNG4SHhyMsLKzQAUuK/C52S0T0NIYsLJ79Lh9VPPslouKT39qj0CNzN2/eRNOmTfPcpmnTprh582ZhH4KIiIiInqDQxZyTkxOuX7+e5zbXr1+Hk5NTYR+CiIiIiJ6g0MVcy5YtsXHjRuzduzfH2/ft24eNGzeiVatWhX0IIiIiInqCQl/NOm3aNGzfvh3+/v7o2LEjWrZsCTc3N8TGxuLgwYPYuXMn7OzsMHXq1KLMS0RERERZFLqYe+6557B7924MGjQI27dvx/bt26EoCgzXUzz77LNYuXIlnnvuuSILS0RERETGnmqZhubNmyMkJARHjx7FuXPn1BUg6tevjxdeeAGKohRVTiIiIiLKQaGLuTfeeAN169bF6NGj0bx5czRv3rwocxERERFRPhT6Aoi1a9fi1q1bRZmFiIiIiAqo0MXcs88+i+jo6KLMQkREREQFVOhi7o033sD27dsRFRVVlHmIiIiIqAAKfc5cjx49cODAATRr1gzjx49Ho0aN4ObmluNFD5UrV36qkERERESUs0IXc56enupUJO+9916u2ymKgoyMjMI+DBERERHlodDF3IABAzj1CBEREZGZFbqYW7lyZRHGICIiIqLCKPQFEERERERkfk+1AgQApKamYseOHTh37hwSExPh5OSE+vXro2PHjrCxsSmKjERERESUi6cq5n777TcMHToUcXFx6pqswKOLHsqXL49vv/0WXbp0eeqQRERERJSzQhdz+/btQ48ePWBhYYE33ngDL774Itzc3BAbG4vDhw9j9erVePXVV7F79260adOmKDMTERER0f9TJOuQWgE0b94cFy5cwLFjx1CnTp1st1+4cAEvvPACfH198fvvvz91UHNLSkqCk5MTEhMT4ejoaO44RPQvNWRh8ex3+aji2S8RFZ/81h6FvgDi3LlzCAgIyLGQAwAfHx/07t0bZ8+eLexDEBEREdETFLqYs7Ozg6ura57blC9fHnZ2doV9CCIiIiJ6gkIXc+3atcPevXvz3Gbv3r1o3759YR+CiIiIiJ6g0MXcvHnzcOvWLQwYMACRkZFGt0VGRqJ///6Ij4/HvHnznjokEREREeWs0Fez9u/fH87OzlizZg3WrVuHypUrq1ezRkREIDMzEz4+PujXr5/R/RRF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" + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Initialize quantum bayesian inference framework\n", + "qb_ba = QBayesian(circuit=qc_ba)\n", + "# Inference\n", + "counts = qb_ba.rejection_sampling(evidence={})\n", + "plot_histogram({c_key: c_val for c_key, c_val in counts.items() if c_val > 0.0001})" + ] + }, + { + "cell_type": "markdown", + "id": "5d22c72ca6352a56", + "metadata": { + "collapsed": false + }, + "source": [ + "## 4. How to Run an Inference" + ] + }, + { + "cell_type": "markdown", + "id": "d66d7e40d62819b6", + "metadata": { + "collapsed": false + }, + "source": [ + "### 4.1 Set Up\n", + "Quantum Bayesian inference is here based on quantum rejection sampling. Quantum rejection sampling plays a pivotal role in the inference process that follows. After the quantum state is manipulated to include evidence, measurement is performed. However, in quantum rejection sampling, only those measurement outcomes that align with the evidence are considered, effectively 'rejecting' irrelevant outcomes, similar to the traditional rejection sampling method.\n", + "\n", + "The synergy of quantum state manipulation with quantum rejection sampling leads to a more efficient inference process compared to classical approaches, harnessing the inherent parallelism of quantum computing to simultaneously process multiple probabilities. This advanced method has significant implications in areas like quantum machine learning and data analysis, where it could outperform classical algorithms in tasks such as pattern recognition and decision-making.\n", + "\n", + "You can use the `inference` method from `QBayesian` to estimate probabilities given evidence." + ] + }, + { + "cell_type": "markdown", + "id": "b3916bfec5e40bfc", + "metadata": { + "collapsed": false + }, + "source": [ + "#### 4.1. Two Node Bayesian Network Example\n", + "Using `QBayesian`, you can draw various probabilistic conclusions. For the Bayesian network with two nodes, this is limited due to the number of variables. However, if we want to know what the probability of P(Y=0|X=1) is, we can do the following:" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "841bce19ea097bf1", + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-03-15T12:25:44.795158Z", + "start_time": "2024-03-15T12:25:44.744036Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": "0.1004712084149367" + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query = {\"Y\": 0}\n", + "evidence = {\"X\": 1}\n", + "# Inference\n", + "qb_2n.inference(query=query, evidence=evidence)" + ] + }, + { + "cell_type": "markdown", + "id": "fe7797d512bc1470", + "metadata": { + "collapsed": false + }, + "source": [ + "#### 4.2. Burglary Alarm Example" + ] + }, + { + "cell_type": "markdown", + "id": "bb0e805d2f7fb30c", + "metadata": { + "collapsed": false + }, + "source": [ + "Here we have more options to choose from. For example, if John calls, you can calculate the probability of a burglary having occurred. Bayesian networks are particularly useful in such scenarios where you have uncertain information (like John calling) and you want to infer the state of a more fundamental variable (like a burglary)." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "5468619791203a79", + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-03-15T12:25:45.014942Z", + "start_time": "2024-03-15T12:25:44.794874Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": "0.0054042995153299" + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query = {\"B\": 1}\n", + "evidence = {\"J\": 1}\n", + "# Inference\n", + "qb_ba.inference(query=query, evidence=evidence)" + ] + }, + { + "cell_type": "markdown", + "id": "5316dde91cf95cc8", + "metadata": { + "collapsed": false + }, + "source": [ + "We can also set the threshold to accept the evidence higher for the inference, and sometimes we can also improve our result by setting the evidence acceptance threshold higher:" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "a5434c7c7c45040a", + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-03-15T12:25:45.806883Z", + "start_time": "2024-03-15T12:25:45.028762Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": "0.0056128979765628" + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Inference\n", + "qb_ba.threshold = 0.97\n", + "qb_ba.inference(query=query, evidence=evidence)" + ] + }, + { + "cell_type": "markdown", + "id": "cf43ad224f163d80", + "metadata": { + "collapsed": false + }, + "source": [ + "And we can also check whether the algorithm converges:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "d01e712eb69a686e", + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-03-15T12:25:45.810056Z", + "start_time": "2024-03-15T12:25:45.806688Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Converged: True\n" + ] + } + ], + "source": [ + "print(\"Converged: \", qb_ba.converged)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/qiskit_machine_learning/algorithms/__init__.py b/qiskit_machine_learning/algorithms/__init__.py index 1c356f1ca..989d6b98f 100644 --- a/qiskit_machine_learning/algorithms/__init__.py +++ b/qiskit_machine_learning/algorithms/__init__.py @@ -1,6 +1,6 @@ # This code is part of a Qiskit project. # -# (C) Copyright IBM 2021, 2023. +# (C) Copyright IBM 2021, 2024. # # This code is licensed under the Apache License, Version 2.0. You may # obtain a copy of this license in the LICENSE.txt file in the root directory @@ -56,6 +56,16 @@ NeuralNetworkClassifier VQC +Inference ++++++++++++ +Algorithms for inference. + +.. autosummary:: + :toctree: ../stubs/ + :nosignatures: + + QBayesian + Regressors ++++++++++ Algorithms for data regression. @@ -78,6 +88,7 @@ OneHotObjectiveFunction, ) from .classifiers import QSVC, PegasosQSVC, VQC, NeuralNetworkClassifier +from .inference import QBayesian from .regressors import QSVR, VQR, NeuralNetworkRegressor __all__ = [ @@ -94,4 +105,5 @@ "QSVR", "NeuralNetworkRegressor", "VQR", + "QBayesian", ] diff --git a/qiskit_machine_learning/algorithms/inference/__init__.py b/qiskit_machine_learning/algorithms/inference/__init__.py new file mode 100644 index 000000000..322bb8f1c --- /dev/null +++ b/qiskit_machine_learning/algorithms/inference/__init__.py @@ -0,0 +1,18 @@ +# This code is part of a Qiskit project. +# +# (C) Copyright IBM 2023, 2024. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +""" Inference Package """ + + +from .qbayesian import QBayesian + +__all__ = ["QBayesian"] diff --git a/qiskit_machine_learning/algorithms/inference/qbayesian.py b/qiskit_machine_learning/algorithms/inference/qbayesian.py new file mode 100644 index 000000000..9621ba5e4 --- /dev/null +++ b/qiskit_machine_learning/algorithms/inference/qbayesian.py @@ -0,0 +1,380 @@ +# This code is part of a Qiskit project. +# +# (C) Copyright IBM 2023, 2024. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +"""Quantum Bayesian Inference""" + +from __future__ import annotations + +import copy +from typing import Tuple, Dict, Set, List +from qiskit import QuantumCircuit, ClassicalRegister +from qiskit.quantum_info import Statevector +from qiskit.circuit.library import GroverOperator +from qiskit.primitives import BaseSampler, Sampler +from qiskit.circuit import Qubit + + +class QBayesian: + r""" + Implements a quantum Bayesian inference (QBI) algorithm that has been developed in [1]. The + Bayesian network must be based on binary random variables (0/1) and represented by a quantum + circuit. The quantum circuit can be passed in various forms as long as it represents the joint + probability distribution of the network. + + For Bayesian networks with random variables that have more than two states, see for example [2]. + + Note that ``QBayesian`` defines an order for the qubits in the circuit. The last qubit in the + circuit will correspond to the most significant bit in the joint probability distribution. For + example, if the random variables A, B, and C are entered into the circuit in this order with + (A=1, B=0 and C=0), the probability is represented by the probability amplitude of quantum + state 001. + + **Example** + + .. code-block:: python + + qc = QuantumCircuit(...) + + qb = QBayesian(qc) + result = qb.inference(query={...}, evidence={...}) + print("Probability of query given evidence: ", result) + + **References** + [1]: Low, Guang Hao, Theodore J. Yoder, and Isaac L. Chuang. "Quantum inference on Bayesian + networks", Physical Review A 89.6 (2014): 062315. + + [2]: Borujeni, Sima E., et al. "Quantum circuit representation of Bayesian networks." + Expert Systems with Applications 176 (2021): 114768. + """ + + # Discrete quantum Bayesian network + def __init__( + self, + circuit: QuantumCircuit, + *, + limit: int = 10, + threshold: float = 0.9, + sampler: BaseSampler | None = None, + ): + """ + Args: + circuit: The quantum circuit that represents the Bayesian network. Each random variable + should be assigned to exactly one register of one qubit. The last qubit in the + circuit corresponds to the most significant bit in the binary string, which + represents the measured quantum state. + limit: The maximum number of times the Grover operator is integrated (2^limit). + threshold (float): The threshold to accept the evidence. For example, if set to 0.9, + this means that each evidence qubit must be equal to the value of the evidence + variable at least 90% of the measurements. + sampler: The sampler primitive used to compute the Bayesian inference. + If ``None`` is given, a default instance of the reference sampler defined + by :class:`~qiskit.primitives.Sampler` will be used. + Raises: + ValueError: If any register in the circuit is not mapped to exactly one qubit. + """ + # Test valid input + for qrg in circuit.qregs: + if qrg.size > 1: + raise ValueError("Every register needs to be mapped to exactly one unique qubit") + # Initialize parameter + self._circ = circuit + self._limit = limit + self._threshold = threshold + if sampler is None: + sampler = Sampler() + self._sampler = sampler + + # Label of register mapped to its qubit + self._label2qubit = {qrg.name: qrg[0] for qrg in self._circ.qregs} + # Label of register mapped to its qubit index bottom up in significance + self._label2qidx = { + qrg.name: self._circ.num_qubits - idx - 1 for idx, qrg in enumerate(self._circ.qregs) + } + # Distribution of samples from rejection sampling + self._samples: Dict[str, float] = {} + # True if rejection sampling converged after limit + self._converged = bool() + + def _get_grover_op(self, evidence: Dict[str, int]) -> GroverOperator: + """ + Constructs a Grover operator based on the provided evidence. The evidence is used to + determine the "good states" that the Grover operator will amplify. + + Args: + evidence: A dictionary representing the evidence with keys as variable labels + and values as states. + Returns: + GroverOperator: The constructed Grover operator. + """ + # Evidence to reversed qubit index sorted by index + num_qubits = self._circ.num_qubits + e2idx = sorted( + [(self._label2qidx[e_key], e_val) for e_key, e_val in evidence.items()], + key=lambda x: x[0], + ) + # Binary format of good states + num_evd = len(e2idx) + bin_str = [ + format(i, f"0{(num_qubits - num_evd)}b") for i in range(2 ** (num_qubits - num_evd)) + ] + # Get good states + good_states = [] + for b in bin_str: + for e_idx, e_val in e2idx: + b = b[:e_idx] + str(e_val) + b[e_idx:] + good_states.append(b) + # Get statevector by transform good states w.r.t its index to 1 and o/w to 0 + oracle = Statevector( + [int(format(i, f"0{num_qubits}b") in good_states) for i in range(2**num_qubits)] + ) + return GroverOperator(oracle, state_preparation=self._circ) + + def _run_circuit(self, circuit: QuantumCircuit) -> Dict[str, float]: + """Run the quantum circuit with the sampler.""" + # Sample from circuit + job = self._sampler.run(circuit) + result = job.result() + # Get the counts of quantum state results + counts = result.quasi_dists[0].nearest_probability_distribution().binary_probabilities() + return counts + + def __power_grover( + self, grover_op: GroverOperator, evidence: Dict[str, int], k: int + ) -> Tuple[QuantumCircuit, Set[Tuple[Qubit, int]]]: + """ + Applies the Grover operator to the quantum circuit 2^k times, measures the evidence qubits, + and returns a tuple containing the updated quantum circuit and a set of the measured + evidence qubits. + + Args: + grover_op: The Grover operator to be applied. + evidence: A dictionary representing the evidence. + k: The power to which the Grover operator is raised. + Returns: + tuple: A tuple containing the updated quantum circuit and a set of the measured evidence + qubits. + """ + # Create circuit + qc = QuantumCircuit(*self._circ.qregs) + qc.append(self._circ, self._circ.qregs) + # Apply Grover operator 2^k times + qc_grover = QuantumCircuit(*self._circ.qregs) + qc_grover.append(grover_op, self._circ.qregs) + qc_grover = qc_grover.power(2**k) + qc.append(qc_grover, self._circ.qregs) + # Add quantum circuit for measuring + qc_measure = QuantumCircuit(*self._circ.qregs) + qc_measure.append(qc, self._circ.qregs) + # Create a classical register with the size of the evidence + measurement_ecr = ClassicalRegister(len(evidence)) + qc_measure.add_register(measurement_ecr) + # Map the evidence qubits to the classical bits and measure them + evidence_qubits = [self._label2qubit[e_key] for e_key in evidence] + qc_measure.measure(evidence_qubits, measurement_ecr) + # Run the circuit with the Grover operator and measurements + e_samples = self._run_circuit(qc_measure) + e_count = {self._label2qubit[e]: 0.0 for e in evidence} + for e_sample_key, e_sample_val in e_samples.items(): + # Go through reverse binary that matches order of qubits + for i, char in enumerate(e_sample_key[::-1]): + if int(char) == 1: + e_count[evidence_qubits[i]] += e_sample_val + # Assign to every evidence qubit if it is measured with high probability (th) 1 o/w 0 + e_meas = { + (e_count_key, int(e_count_val >= self._threshold)) + for e_count_key, e_count_val in e_count.items() + } + return qc, e_meas + + def _format_samples(self, samples: Dict[str, float], evidence: List[str]) -> Dict[str, float]: + """Transforms samples keys back to their variables names.""" + f_samples: Dict[str, float] = {} + for smpl_key, smpl_val in samples.items(): + q_str, e_str = "", "" + for var_name, var_idx in sorted(self._label2qidx.items(), key=lambda x: -x[1]): + if var_name in evidence: + e_str += f"{var_name}={smpl_key[var_idx]}," + else: + q_str += f"{var_name}={smpl_key[var_idx]}," + if evidence: + f_samples[f"P({q_str[:-1]}|{e_str[:-1]})"] = smpl_val + else: + f_samples[f"P({q_str[:-1]})"] = smpl_val + return f_samples + + def rejection_sampling( + self, evidence: Dict[str, int], format_res: bool = False + ) -> Dict[str, float]: + """ + Performs quantum rejection sampling given the evidence. + + Args: + evidence: The keys of the dictionary are the evidence variables that are linked to the + corresponding quantum register with their names and values (0/1). If evidence is + empty, it measures all qubits. If evidence is given, it uses the Grover operator for + amplitude amplification and repeats until the evidence matches or limit is reached. + format_res: If true, maps the output back to variable names. For example, the output + {'100': 0.23} with evidence A=0, B=0 will be mapped to {'P(C=1|A=0,B=0)': 0.23}. + Returns: + A dictionary with the probability distribution of the samples given the evidence, where + the keys are the sequential values of the variables. Note that the last variable value + appears as the first character for the key. If format_res is true, the output will be + mapped back to the variable names, for example {'P(C=1|A=0,B=0)': 0.23}. + """ + # If evidence is empty + if len(evidence) == 0: + # Create circuit + qc = QuantumCircuit(*self._circ.qregs) + qc.append(self._circ, self._circ.qregs) + # Measure + qc.measure_all() + # Run circuit + self._samples = self._run_circuit(qc) + else: + # Get Grover operator if evidence not empty + grover_op = self._get_grover_op(evidence) + # Amplitude amplification + true_e = {(self._label2qubit[e_key], e_val) for e_key, e_val in evidence.items()} + meas_e: Set[Tuple[str, int]] = set() + best_qc, best_inter = QuantumCircuit(), -1 + self._converged = False + k = -1 + # If the measurement of the evidence qubits matches the evidence stop + while (true_e != meas_e) and (k < self._limit): + # Increment power + k += 1 + # Create circuit with 2^k times Grover operator + qc, meas_e = self.__power_grover(grover_op=grover_op, evidence=evidence, k=k) + # Test number of + if len(true_e.intersection(meas_e)) > best_inter: + best_qc = qc + if true_e == meas_e: + self._converged = True + # Create a classical register with the size of the evidence + best_qc_meas = QuantumCircuit(*self._circ.qregs) + best_qc_meas.append(best_qc, self._circ.qregs) + measurement_qcr = ClassicalRegister(self._circ.num_qubits - len(evidence)) + best_qc_meas.add_register(measurement_qcr) + # Map the query qubits to the classical bits and measure them + query_qubits = [ + (label, self._label2qidx[label], qubit) + for label, qubit in self._label2qubit.items() + if label not in evidence + ] + query_qubits_sorted = sorted(query_qubits, key=lambda x: x[1], reverse=True) + # Measure query variables and return their count + best_qc_meas.measure([q[2] for q in query_qubits_sorted], measurement_qcr) + # Run circuit + counts = self._run_circuit(best_qc_meas) + # Build default string with evidence + query_string = "" + var_idx_sorted = [ + label for label, _ in sorted(self._label2qidx.items(), key=lambda x: x[1]) + ] + for var in var_idx_sorted: + if var in evidence: + query_string += str(evidence[var]) + else: + query_string += "q" + # Retrieve valid samples + self._samples = {} + # Replace placeholder q with query variables from samples + for key, val in counts.items(): + query = query_string + for char in key: + query = query.replace("q", char, 1) + self._samples[query] = val + if not format_res: + return copy.deepcopy(self._samples) + else: + return self._format_samples(self._samples, list(evidence.keys())) + + def inference( + self, + query: Dict[str, int], + evidence: Dict[str, int] = None, + ) -> float: + """ + Performs quantum inference for the query variables given the evidence. It uses quantum + rejection sampling if evidence is given and calculates the probability of the query. + + Args: + query: The keys of the dictionary are the query variables that are linked to the + corresponding quantum registers with their names and values (0/1). If the query + variables are a real subset of all variables without the evidence, the query will be + marginalized. + evidence: The evidence variables. If evidence is a dictionary, the rejection sampling is + executed with the keys representing the variables linked to the corresponding + quantum register by their names and values (0/1). If evidence is ``None``, the + default, then samples from the previous rejection sampling are used. + Returns: + The probability of the query given the evidence. + Raises: + ValueError: If evidence is required for rejection sampling and ``None`` is given. + """ + if evidence is not None: + self.rejection_sampling(evidence) + elif not self._samples: + raise ValueError("Provide evidence or indicate no evidence with an empty dictionary") + # Get sorted indices of query qubits + query_indices_rev = [(self._label2qidx[q_key], q_val) for q_key, q_val in query.items()] + # Get probability of query + res = 0.0 + for sample_key, sample_val in self._samples.items(): + add = True + for q_idx, q_val in query_indices_rev: + if int(sample_key[q_idx]) != q_val: + add = False + break + if add: + res += sample_val + return res + + @property + def converged(self) -> bool: + """Returns ``True`` if a solution for the evidence with the given threshold was found + without reaching the maximum number of times the Grover operator was applied (2^limit).""" + return self._converged + + @property + def samples(self) -> Dict[str, float]: + """Returns the samples generated from the rejection sampling.""" + return self._samples + + @property + def limit(self) -> int: + """Returns the maximum number of times the Grover operator can be applied (2^limit).""" + return self._limit + + @limit.setter + def limit(self, limit: int): + """Set the maximum number of times the Grover operator can be applied (2^limit).""" + self._limit = limit + + @property + def sampler(self) -> BaseSampler: + """Returns the sampler primitive used to compute the samples.""" + return self._sampler + + @sampler.setter + def sampler(self, sampler: BaseSampler): + """Set the sampler primitive used to compute the samples.""" + self._sampler = sampler + + @property + def threshold(self) -> float: + """Returns the threshold to accept the evidence.""" + return self._threshold + + @threshold.setter + def threshold(self, threshold: float): + """Set the threshold to accept the evidence.""" + self._threshold = threshold diff --git a/releasenotes/notes/add-quantum-bayesian-inference-92c6025432d9b7e0.yaml b/releasenotes/notes/add-quantum-bayesian-inference-92c6025432d9b7e0.yaml new file mode 100644 index 000000000..f226b0027 --- /dev/null +++ b/releasenotes/notes/add-quantum-bayesian-inference-92c6025432d9b7e0.yaml @@ -0,0 +1,39 @@ +--- +features: + - | + Added a new class :class:`~qiskit_machine_learning.algorithms.QBayesian` that does quantum Bayesian inference on a + a quantum circuit representing a Bayesian network with binary random variables. + + The computational complexity is reduced from :math:`O(nmP(e)^{-1})` to :math:`O(n2^{m}P(e)^{-\frac{1}{2}})` per + sample, where n is the number of nodes in the Bayesian network with at most m parents per node and e the evidence. + + At least a quantum circuit that represents the Bayesian network has to be provided. A quantum circuit can be passed + in various forms as long as it represents the joint probability distribution of the Bayesian network. Note that + :class:`~qiskit_machine_learning.algorithms.QBayesian` defines an order for the qubits in the circuit. The last + qubit in the circuit will correspond to the most significant bit in the joint probability distribution. For example, + if the random variables A, B, and C are entered into the circuit in this order with (A=1, B=0 and C=0), the + probability is represented by the probability amplitude of quantum state 001. + + An example for using this class is as follows: + + .. code-block:: python + + from qiskit import QuantumCircuit + from qiskit_machine_learning.algorithms import QBayesian + + # Define a quantum circuit + qc = QuantumCircuit(...) + + # Initialize the framework + qb = QBayesian(qc) + + # Perform inference + result = qb.inference(query={...}, evidence={...}) + + print("Probability of query given evidence:", result) + + - | + For the new :class:`~qiskit_machine_learning.algorithms.QBayesian` class, a tutorial was added. Please refer to: + + - New `QBI tutorial <../tutorials/13_quantum_bayesian_inference.html>`__ + that introduces a step-by-step approach for how to do quantum Bayesian inference on a Bayesian network. diff --git a/releasenotes/notes/fix-fid_statevector_kernel-pickling-b7fa2b13a15ec9c6.yaml b/releasenotes/notes/fix-fid_statevector_kernel-pickling-b7fa2b13a15ec9c6.yaml index 34c512b83..fbdcb8dee 100644 --- a/releasenotes/notes/fix-fid_statevector_kernel-pickling-b7fa2b13a15ec9c6.yaml +++ b/releasenotes/notes/fix-fid_statevector_kernel-pickling-b7fa2b13a15ec9c6.yaml @@ -1,4 +1,5 @@ --- fixes: - | - Fixed a bug where :class:`.FidelityStatevectorKernel` threw an error when pickled. \ No newline at end of file + Fixed a bug where :class:`.FidelityStatevectorKernel` threw an error when pickled. + diff --git a/test/algorithms/inference/__init__.py b/test/algorithms/inference/__init__.py new file mode 100644 index 000000000..ceef869a8 --- /dev/null +++ b/test/algorithms/inference/__init__.py @@ -0,0 +1,11 @@ +# This code is part of a Qiskit project. +# +# (C) Copyright IBM 2023, 2024. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. diff --git a/test/algorithms/inference/test_qbayesian.py b/test/algorithms/inference/test_qbayesian.py new file mode 100644 index 000000000..a4f5a2693 --- /dev/null +++ b/test/algorithms/inference/test_qbayesian.py @@ -0,0 +1,210 @@ +# This code is part of a Qiskit project. +# +# (C) Copyright IBM 2023, 2024. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +""" Test Quantum Bayesian Inference """ + +import unittest +from test import QiskitMachineLearningTestCase + +import numpy as np +from qiskit_algorithms.utils import algorithm_globals +from qiskit import QuantumCircuit +from qiskit.circuit import QuantumRegister +from qiskit.primitives import Sampler +from qiskit_machine_learning.algorithms import QBayesian + + +class TestQBayesianInference(QiskitMachineLearningTestCase): + """Test QBayesianInference Algorithm""" + + def setUp(self): + super().setUp() + algorithm_globals.random_seed = 10598 + # Quantum Bayesian inference + qc = self._create_bayes_net() + self.qbayesian = QBayesian(qc) + + def _create_bayes_net(self): + # Probabilities + theta_a = 2 * np.arcsin(np.sqrt(0.25)) + theta_b_na = 2 * np.arcsin(np.sqrt(0.6)) + theta_b_a = 2 * np.arcsin(np.sqrt(0.7)) + theta_c_nbna = 2 * np.arcsin(np.sqrt(0.1)) + theta_c_nba = 2 * np.arcsin(np.sqrt(0.55)) + theta_c_bna = 2 * np.arcsin(np.sqrt(0.7)) + theta_c_ba = 2 * np.arcsin(np.sqrt(0.9)) + # Random variables + qr_a = QuantumRegister(1, name="A") + qr_b = QuantumRegister(1, name="B") + qr_c = QuantumRegister(1, name="C") + # Define a 3-qubit quantum circuit + qc = QuantumCircuit(qr_a, qr_b, qr_c, name="Bayes net") + # P(A) + qc.ry(theta_a, 0) + # P(B|-A) + qc.x(0) + qc.cry(theta_b_na, qr_a, qr_b) + qc.x(0) + # P(B|A) + qc.cry(theta_b_a, qr_a, qr_b) + # P(C|-B,-A) + qc.x(0) + qc.x(1) + qc.mcry(theta_c_nbna, [qr_a[0], qr_b[0]], qr_c[0]) + qc.x(0) + qc.x(1) + # P(C|-B,A) + qc.x(1) + qc.mcry(theta_c_nba, [qr_a[0], qr_b[0]], qr_c[0]) + qc.x(1) + # P(C|B,-A) + qc.x(0) + qc.mcry(theta_c_bna, [qr_a[0], qr_b[0]], qr_c[0]) + qc.x(0) + # P(C|B,A) + qc.mcry(theta_c_ba, [qr_a[0], qr_b[0]], qr_c[0]) + return qc + + def test_rejection_sampling(self): + """Test rejection sampling with different amount of evidence""" + test_cases = [{"A": 0, "B": 0}, {"A": 0}, {}] + true_res = [ + {"000": 0.9, "100": 0.1}, + {"000": 0.36, "100": 0.04, "010": 0.18, "110": 0.42}, + { + "000": 0.27, + "001": 0.03375, + "010": 0.135, + "011": 0.0175, + "100": 0.03, + "101": 0.04125, + "110": 0.315, + "111": 0.1575, + }, + ] + for evd, res in zip(test_cases, true_res): + samples = self.qbayesian.rejection_sampling(evidence=evd) + self.assertTrue( + np.all( + [ + np.isclose(res[sample_key], sample_val, atol=0.08) + for sample_key, sample_val in samples.items() + ] + ) + ) + + def test_rejection_sampling_format_res(self): + """Test rejection sampling with different result format""" + test_cases = [{"A": 0, "C": 1}, {"C": 1}, {}] + true_res = [ + {"P(B=0|A=0,C=1)", "P(B=1|A=0,C=1)"}, + {"P(A=0,B=0|C=1)", "P(A=1,B=0|C=1)", "P(A=0,B=1|C=1)", "P(A=1,B=1|C=1)"}, + { + "P(A=0,B=0,C=0)", + "P(A=1,B=0,C=0)", + "P(A=0,B=1,C=0)", + "P(A=1,B=1,C=0)", + "P(A=0,B=0,C=1)", + "P(A=1,B=0,C=1)", + "P(A=0,B=1,C=1)", + "P(A=1,B=1,C=1)", + }, + ] + for evd, res in zip(test_cases, true_res): + self.assertTrue( + res == set(self.qbayesian.rejection_sampling(evidence=evd, format_res=True).keys()) + ) + + def test_inference(self): + """Test inference with different amount of evidence""" + test_q_1, test_e_1 = ({"B": 1}, {"A": 1, "C": 1}) + test_q_2 = {"B": 0} + test_q_3 = {} + test_q_4, test_e_4 = ({"B": 1}, {"A": 0}) + true_res = [0.79, 0.21, 1, 0.6] + res = [] + samples = [] + # 1. Query basic inference + res.append(self.qbayesian.inference(query=test_q_1, evidence=test_e_1)) + samples.append(self.qbayesian.samples) + # 2. Query basic inference + res.append(self.qbayesian.inference(query=test_q_2)) + samples.append(self.qbayesian.samples) + # 3. Query marginalized inference + res.append(self.qbayesian.inference(query=test_q_3)) + samples.append(self.qbayesian.samples) + # 4. Query marginalized inference + res.append(self.qbayesian.inference(query=test_q_4, evidence=test_e_4)) + # Correct inference + self.assertTrue(np.all(np.isclose(true_res, res, atol=0.04))) + # No change in samples + self.assertTrue(samples[0] == samples[1]) + + def test_parameter(self): + """Tests parameter of methods""" + # Test set threshold + self.qbayesian.threshold = 0.9 + self.qbayesian.rejection_sampling(evidence={"A": 1}) + self.assertTrue(self.qbayesian.threshold == 0.9) + # Test set limit + # Not converged + self.qbayesian.limit = 0 + self.qbayesian.rejection_sampling(evidence={"B": 1}) + self.assertFalse(self.qbayesian.converged) + self.assertTrue(self.qbayesian.limit == 0) + # Converged + self.qbayesian.limit = 1 + self.qbayesian.rejection_sampling(evidence={"B": 1}) + self.assertTrue(self.qbayesian.converged) + self.assertTrue(self.qbayesian.limit == 1) + # Test sampler + sampler = Sampler() + self.qbayesian.sampler = sampler + self.qbayesian.inference(query={"B": 1}, evidence={"A": 0, "C": 0}) + self.assertTrue(self.qbayesian.sampler == sampler) + # Create a quantum circuit with a register that has more than one qubit + with self.assertRaises(ValueError, msg="No ValueError in constructor with invalid input."): + QBayesian(QuantumCircuit(QuantumRegister(2, "qr"))) + # Test invalid inference without evidence or generated samples + with self.assertRaises(ValueError, msg="No ValueError in inference with invalid input."): + QBayesian(QuantumCircuit(QuantumRegister(1, "qr"))).inference({"A": 0}) + + def test_trivial_circuit(self): + """Tests trivial quantum circuit""" + # Define rotation angles + theta_a = 2 * np.arcsin(np.sqrt(0.2)) + theta_b_a = 2 * np.arcsin(np.sqrt(0.9)) + theta_b_na = 2 * np.arcsin(np.sqrt(0.3)) + # Define quantum registers + qr_a = QuantumRegister(1, name="A") + qr_b = QuantumRegister(1, name="B") + # Define a 2-qubit quantum circuit + qc = QuantumCircuit(qr_a, qr_b, name="Bayes net small") + qc.ry(theta_a, 0) + qc.cry(theta_b_a, control_qubit=qr_a, target_qubit=qr_b) + qc.x(0) + qc.cry(theta_b_na, control_qubit=qr_a, target_qubit=qr_b) + qc.x(0) + # Inference + self.assertTrue( + np.all( + np.isclose( + 0.1, + QBayesian(circuit=qc).inference(query={"B": 0}, evidence={"A": 1}), + atol=0.04, + ) + ) + ) + + +if __name__ == "__main__": + unittest.main()