From 5ec14807249e9743539d43364782b78b5c782d58 Mon Sep 17 00:00:00 2001 From: axif Date: Thu, 12 Feb 2026 20:23:59 +0600 Subject: [PATCH 1/8] feat: Add Quantum Counting algorithm implementation --- README.md | 1 + .../textbook/Quantum_Counting_Algorithm.ipynb | 536 ++++++++++++++++++ .../algorithms/quantum_counting/__init__.py | 21 + .../quantum_counting/quantum_counting.md | 7 + .../quantum_counting/quantum_counting.py | 345 +++++++++++ .../quantum_counting/test_quantum_counting.py | 217 +++++++ 6 files changed, 1127 insertions(+) create mode 100644 notebooks/textbook/Quantum_Counting_Algorithm.ipynb create mode 100644 src/braket/experimental/algorithms/quantum_counting/__init__.py create mode 100644 src/braket/experimental/algorithms/quantum_counting/quantum_counting.md create mode 100644 src/braket/experimental/algorithms/quantum_counting/quantum_counting.py create mode 100644 test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py diff --git a/README.md b/README.md index d234ca0d..4624df42 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Running notebooks locally requires additional dependencies located in [notebooks | Quantum Circuit Born Machine | [Quantum_Circuit_Born_Machine.ipynb](notebooks/textbook/Quantum_Circuit_Born_Machine.ipynb) | [Benedetti2019](https://www.nature.com/articles/s41534-019-0157-8), [Liu2018](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.98.062324) | | QFT | [Quantum_Fourier_Transform.ipynb](notebooks/textbook/Quantum_Fourier_Transform.ipynb) | [Coppersmith2002](https://arxiv.org/abs/quant-ph/0201067) | | QPE | [Quantum_Phase_Estimation_Algorithm.ipynb](notebooks/textbook/Quantum_Phase_Estimation_Algorithm.ipynb) | [Kitaev1995](https://arxiv.org/abs/quant-ph/9511026) | +| Quantum Counting | [Quantum_Counting_Algorithm.ipynb](notebooks/textbook/Quantum_Counting_Algorithm.ipynb) | [Brassard1998](https://arxiv.org/abs/quant-ph/9805082) | | Quantum Walk | [Quantum_Walk.ipynb](notebooks/textbook/Quantum_Walk.ipynb) | [Childs2002](https://arxiv.org/abs/quant-ph/0209131) | |Shor's| [Shors_Algorithm.ipynb](notebooks/textbook/Shors_Algorithm.ipynb) | [Shor1998](https://arxiv.org/abs/quant-ph/9508027) | | Simon's | [Simons_Algorithm.ipynb](notebooks/textbook/Simons_Algorithm.ipynb) | [Simon1997](https://epubs.siam.org/doi/10.1137/S0097539796298637) | diff --git a/notebooks/textbook/Quantum_Counting_Algorithm.ipynb b/notebooks/textbook/Quantum_Counting_Algorithm.ipynb new file mode 100644 index 00000000..ddf6aa20 --- /dev/null +++ b/notebooks/textbook/Quantum_Counting_Algorithm.ipynb @@ -0,0 +1,536 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Quantum Counting Algorithm\n", + "\n", + "The Quantum Counting algorithm, introduced by Brassard, Høyer, and Tapp [1], counts the number of marked items $M$ in an unstructured database of $N = 2^n$ elements. It combines **Grover's search operator** with **Quantum Phase Estimation (QPE)** to achieve a quadratic speedup over classical counting, requiring only $O(\\sqrt{N})$ oracle queries instead of the classical $\\Theta(N)$.\n", + "\n", + "**Key idea:** The Grover operator $G = D \\cdot O$ has eigenvalues $e^{\\pm i\\theta}$, where $\\theta$ satisfies $\\sin^2(\\theta/2) = M/N$. By applying QPE to $G$, we estimate $\\theta$ and hence determine $M$." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## References\n", + "\n", + "[[1] G. Brassard, P. Høyer, and A. Tapp, \"Quantum Counting\", Proceedings of ICALP 1998](https://arxiv.org/abs/quant-ph/9805082)\n", + "\n", + "[[2] M. Nielsen and I. Chuang, Quantum Computation and Quantum Information, Cambridge University Press, 2010](https://www.cambridge.org/highereducation/books/quantum-computation-and-quantum-information/01E10196D0A682A6AEFFEA52D53BE9AE)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from braket.circuits import Circuit\n", + "from braket.devices import LocalSimulator\n", + "\n", + "from braket.experimental.algorithms.quantum_counting import (\n", + " build_grover_matrix,\n", + " build_oracle_matrix,\n", + " get_quantum_counting_results,\n", + " quantum_counting_circuit,\n", + " run_quantum_counting,\n", + ")\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Background\n", + "\n", + "### The Grover Operator\n", + "\n", + "Given an oracle $O$ that marks certain states by flipping their phase ($O|x\\rangle = (-1)^{f(x)}|x\\rangle$), and the Grover diffusion operator $D = 2|s\\rangle\\langle s| - I$, the Grover operator is:\n", + "\n", + "$$G = D \\cdot O$$\n", + "\n", + "In the 2D subspace of marked ($|\\beta\\rangle$) and unmarked ($|\\alpha\\rangle$) states, $G$ acts as a rotation by angle $\\theta$:\n", + "\n", + "$$\\sin^2(\\theta/2) = M/N$$\n", + "\n", + "### QPE on the Grover Operator\n", + "\n", + "The eigenvalues of $G$ are $e^{\\pm i\\theta}$. QPE with $t$ precision (counting) qubits estimates the phase $\\varphi = \\theta/(2\\pi)$ as a $t$-bit fraction $y/2^t$. From $\\varphi$, we recover:\n", + "\n", + "$$M = N \\cdot \\sin^2(\\pi \\varphi)$$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prepare the Oracle and Grover Operator" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Oracle matrix:\n", + "[[ 1. 0. 0. 0.]\n", + " [ 0. 1. 0. 0.]\n", + " [ 0. 0. 1. 0.]\n", + " [ 0. 0. 0. -1.]]\n", + "\n", + "Grover operator G:\n", + "[[-0.5 0.5 0.5 -0.5]\n", + " [ 0.5 -0.5 0.5 -0.5]\n", + " [ 0.5 0.5 -0.5 -0.5]\n", + " [ 0.5 0.5 0.5 0.5]]\n", + "\n", + "Eigenvalues of G: [-1. +0.j 0.5+0.866j 0.5-0.866j -1. +0.j ]\n" + ] + } + ], + "source": [ + "# Search space: n_search = 2 qubits -> N = 4 elements\n", + "# Mark state |3> (binary '11')\n", + "n_search = 2\n", + "marked_states = [3]\n", + "N = 2**n_search\n", + "\n", + "# Build the oracle and Grover matrices\n", + "oracle = build_oracle_matrix(n_search, marked_states)\n", + "print(\"Oracle matrix:\")\n", + "print(oracle)\n", + "\n", + "grover = build_grover_matrix(n_search, marked_states)\n", + "print(\"\\nGrover operator G:\")\n", + "print(np.round(grover, 4))\n", + "\n", + "# Verify eigenvalues\n", + "eigenvalues = np.linalg.eigvals(grover)\n", + "print(f\"\\nEigenvalues of G: {np.round(eigenvalues, 4)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Build and Print the Quantum Counting Circuit" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Counting qubits: [0, 1, 2, 3]\n", + "Search qubits: [4, 5]\n", + "Search space size: N = 4\n", + "Marked states: [3] (M = 1)\n", + "\n", + "Quantum Counting Circuit:\n", + "T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ 12 │ Result Types │\n", + " ┌───┐ ┌───┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌───┐ ┌─────────────┐ \n", + "q0 : ─┤ H ├───────────────────┤ U ├─────────────x────────────────────────────────────────────────────────────────────┤ PHASE(-0.39) ├───────┤ PHASE(-0.79) ├─┤ PHASE(-1.57) ├─┤ H ├─┤ Probability ├─\n", + " └───┘ └─┬─┘ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └───┘ └──────┬──────┘ \n", + " ┌───┐ ┌───┐ │ │ ┌──────────────┐ ┌──────────────┐ │ ┌───┐ │ │ ┌──────┴──────┐ \n", + "q1 : ─┤ H ├─────────────┤ U ├───┼──────x────────┼──────────────────────────────────┤ PHASE(-0.79) ├─┤ PHASE(-1.57) ├────────┼─────────┤ H ├────────┼────────────────●───────────────┤ Probability ├─\n", + " └───┘ └─┬─┘ │ │ │ └──────┬───────┘ └──────┬───────┘ │ └───┘ │ └──────┬──────┘ \n", + " ┌───┐ ┌───┐ │ │ │ │ ┌──────────────┐ ┌───┐ │ │ │ │ ┌──────┴──────┐ \n", + "q2 : ─┤ H ├───────┤ U ├───┼─────┼──────x────────┼───────────┤ PHASE(-1.57) ├─┤ H ├────────┼────────────────●────────────────┼──────────────────────●────────────────────────────────┤ Probability ├─\n", + " └───┘ └─┬─┘ │ │ │ └──────┬───────┘ └───┘ │ │ └──────┬──────┘ \n", + " ┌───┐ ┌───┐ │ │ │ │ ┌───┐ │ │ │ ┌──────┴──────┐ \n", + "q3 : ─┤ H ├─┤ U ├───┼─────┼─────┼───────────────x─────┤ H ├────────●──────────────────────●─────────────────────────────────●───────────────────────────────────────────────────────┤ Probability ├─\n", + " └───┘ └─┬─┘ │ │ │ └───┘ └──────┬──────┘ \n", + " ┌───┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌──────┴──────┐ \n", + "q4 : ─┤ H ├─┤ U ├─┤ U ├─┤ U ├─┤ U ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ Probability ├─\n", + " └───┘ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ └──────┬──────┘ \n", + " ┌───┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌──────┴──────┐ \n", + "q5 : ─┤ H ├─┤ U ├─┤ U ├─┤ U ├─┤ U ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ Probability ├─\n", + " └───┘ └───┘ └───┘ └───┘ └───┘ └─────────────┘ \n", + "T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ 12 │ Result Types │\n" + ] + } + ], + "source": [ + "# Use 4 counting qubits (t = 4) for good precision\n", + "n_counting = 4\n", + "counting_qubits = list(range(n_counting))\n", + "search_qubits = list(range(n_counting, n_counting + n_search))\n", + "\n", + "print(f\"Counting qubits: {counting_qubits}\")\n", + "print(f\"Search qubits: {search_qubits}\")\n", + "print(f\"Search space size: N = {N}\")\n", + "print(f\"Marked states: {marked_states} (M = {len(marked_states)})\")\n", + "\n", + "# Build the circuit\n", + "circ = Circuit()\n", + "circ = quantum_counting_circuit(circ, counting_qubits, search_qubits, grover)\n", + "\n", + "print(\"\\nQuantum Counting Circuit:\")\n", + "print(circ)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Run on a Local Simulator" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Quantum Counting Running...\n", + "Quantum Counting Run Complete\n", + "\n", + "Quantum Counting Results:\n", + "Measurement counts: Counter({'110111': 176, '001111': 152, '001101': 63, '001110': 62, '111011': 60, '001100': 59, '110110': 58, '110100': 58, '001011': 53, '110101': 48, '111111': 18, '001001': 16, '000111': 15, '111000': 15, '111001': 13, '110011': 13, '111010': 13, '001000': 10, '001010': 10, '010000': 8, '111101': 5, '110001': 5, '000011': 5, '110010': 5, '010001': 5, '010111': 4, '101110': 4, '011111': 4, '010011': 4, '100110': 3, '010110': 3, '011000': 3, '000110': 3, '011110': 3, '101111': 2, '011010': 2, '000000': 2, '101000': 2, '110000': 2, '010010': 2, '100010': 1, '101010': 1, '101001': 1, '010101': 1, '101011': 1, '000001': 1, '100011': 1, '011001': 1, '000101': 1, '010100': 1, '100100': 1, '011101': 1})\n", + "Counting register results: {'0011': 336, '1101': 340, '0010': 89, '1110': 101, '1111': 23, '0001': 19, '1001': 4, '1000': 2, '1100': 25, '1011': 6, '1010': 5, '0100': 19, '0101': 9, '0000': 8, '0110': 6, '0111': 8}\n", + "Phase estimates: [0.1875, 0.8125, 0.125, 0.875, 0.9375, 0.0625, 0.5625, 0.5, 0.75, 0.6875, 0.625, 0.25, 0.3125, 0.0, 0.375, 0.4375]\n", + "Estimated item counts: [np.float64(1.2346331352698203), np.float64(1.2346331352698203), np.float64(0.585786437626905), np.float64(0.5857864376269053), np.float64(0.15224093497742702), np.float64(0.15224093497742647), np.float64(3.8477590650225735), np.float64(4.0), np.float64(2.0000000000000004), np.float64(2.765366864730181), np.float64(3.414213562373095), np.float64(1.9999999999999996), np.float64(2.7653668647301797), np.float64(0.0), np.float64(3.414213562373095), np.float64(3.8477590650225735)]\n", + "Best estimate of M: 1.2346331352698203\n", + "Search space size N: 4\n", + "\n", + "--- Summary ---\n", + "Actual M = 1\n", + "Estimated M ≈ 1.2346\n", + "Absolute error: 0.2346\n" + ] + } + ], + "source": [ + "# Run on local simulator\n", + "device = LocalSimulator()\n", + "print(\"Quantum Counting Running...\")\n", + "task = run_quantum_counting(circ, device, shots=1000)\n", + "print(\"Quantum Counting Run Complete\")\n", + "\n", + "# Get and display results\n", + "print(\"\\nQuantum Counting Results:\")\n", + "results = get_quantum_counting_results(\n", + " task, counting_qubits, search_qubits, verbose=True\n", + ")\n", + "\n", + "print(f\"\\n--- Summary ---\")\n", + "print(f\"Actual M = {len(marked_states)}\")\n", + "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")\n", + "print(f\"Absolute error: {abs(len(marked_states) - results['best_estimate']):.4f}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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XBUqVNDzzz+vb775Ri+//LJq166t3r17ZzqtZcuW6fDhwxo2bFiWjsYeOHBAzZo108mTJzV06FCVKFFCH374oa699lrNmDFD//nPf7KV05EjR9SxY0f16NFDN954o2bMmKHhw4crOjpanTp1Us2aNTV69Gg99dRTGjhwoKffmzVrdt7pTps2TceOHdNdd90ll8ull156ST169NDOnTs9R8e//vpr3XTTTYqOjtaYMWN05MgR9evXL8MjthfDXRiHhoZ6hj333HN68skndeONN6p///46dOiQ3nrrLbVq1Uq//vqrQkNDlZSUpA4dOigxMdHT13/99ZfmzJmjo0ePKiQk5JLiGjt2rOe668cff1ySFB4eLunsD1BjxoxR//791bhxYyUkJGj16tX65ZdfdM0112Q6zTVr1igpKUlXXXVVpm0ef/xxTZky5YJHu8+cOeP5ceFCwsLClCfP/46RHDt2TMOHD9djjz2miIiILE0jKypVqqSYmBh98skn6tSpkyTp22+/VXx8vG6++eYM8zly5IhSUlIuOO3ChQurcOHC2YorJCREVapU0Y8//qj7778/W9MAAL8zAEDAOXr0qEmy7t27n7fdtddea5IsISHBzMz69OljFStWTNfu6aeftnM3+SdPnkzXrkOHDla5cmWvYRUrVjRJtnTpUs+wgwcPWlBQkD344IOeYZ999plJsu+//z7ddCXZ008/nW54xYoVrU+fPp7XkyZNMknWoUMHS01N9QyPiYkxl8tld999t2dYcnKylStXzlq3bp1uumm98cYbJsm++OKL87ZzGzZsmEmyH374wTPs2LFjFhkZaZUqVbKUlBSvWHft2uX1/u+//z7d59C6dWuTZFOmTPEMS0xMtIiICOvZs6dn2KpVq0ySTZo0KV1c5/btrl27TJKVKFHCDh8+7Bn+5ZdfmiSbPXu2Z1h0dLSVK1fOjh075hm2ePFik5Th8nKu1q1bW40aNezQoUN26NAh27Jliz388MMmybp06eJpt3v3bsubN68999xzXu9fv3695cuXzzP8119/NUn22WefZTpPd34ZfRbnLk8Z9UWtWrUyXDbq1q3rFXNWvffeeybJ1q9fn25cxYoVPdO84447rGDBgrZv3z4z+9/ykDZX97Cs/J27fD300EMWGRlpp0+fTjfv7HB/dqtWrbK3337bihUr5tk23HDDDXb11VdnOh/3tuFCfxmt+25FihTx2gZkpH379lazZs1s5wgA/saRbgAIQMeOHZMkFStW7Lzt3OOPHTt2wbbnKlSokOf/8fHxOnPmjFq3bq25c+cqPj7e62hjVFSU1xH3UqVKqXr16tq5c+dFzTOr+vXr53X6aZMmTbRixQr169fPMyxv3rxq2LCh1qxZc95pJSQkSLrwZ+n2zTffqHHjxmrRooVnWNGiRTVw4ECNGDFCmzZtUu3atS8mHc800l4TXaBAATVu3PiSP8ObbrpJxYsX97x295N7uvv27dP69ev12GOPeV0/27p1a0VHR3s+nwvZsmVLusscrr32Wr3//vue1zNnzlRqaqpuvPFGr2uAIyIidOWVV+r777/XY4895lm25s6dq86dO2f7KGh2hIaGauPGjdq2bZuuvPLKLL/vn3/+kSSvzzojTzzxhKZOnaoXXnhBb7zxRoZt6tate8HT2d3SHs3+/fff9cYbb+iTTz7J0Rubud14440aNmyY5syZo44dO2rOnDnnPWL/8ccf69SpUxec7qVei128eHH9+uuvlzQNAPAnim4ACEBpi+nzOXbsmFwul0qWLHnR8/jxxx/19NNPa8WKFTp58qTXuHOL7goVKqR7f/HixXXkyJGLnm9WnDs/dyzly5dPN/xCMQQHB0u68Gfp9scff2T4bGD3qfJ//PFHtorucuXKpbuOtXjx4lq3bt1FTyutcz8rd1Ho/lz++OMPSVLVqlXTvbdq1ar65ZdfsjSfSpUqaeLEiUpNTdWOHTv03HPP6dChQ153z962bZvMLNNi1n26e2RkpB544AG99tpr+vjjj9WyZUtde+216tWr1yWfWn4ho0ePVvfu3VWtWjXVrl1bHTt21O233646depk6f12gXsIVK5cWbfffrveffddPfrooxm2KV68eKbXhp/Pfffdp2bNmqlnz54X/d6sKFWqlGJjYzVt2jSdPHlSKSkpuv766zNt37x5c5/EcS4zy/I14AAQiCi6ASAAhYSEqGzZshcsyNatW6dy5cqpQIECkpTpF9Nzr7vcsWOH2rVrpxo1aui1115T+fLlVaBAAX3zzTd6/fXX0z17ObNroS9UgFxIZteDZja/jIZfKIYaNWpIktavX6/rrrvu4gI8j6x+1m6++gx9Nd1zFSlSxKtQbN68ua666io99thjnqOhqampcrlc+vbbbzOMK+2R9ldffVV9+/bVl19+qXnz5mno0KEaM2aMVq5cmeEPFG5ZuYb4fFq1aqUdO3Z45vvee+/p9ddf14QJE9S/f/9M31eiRAlJZ3/MKFeu3Hnn4b4j/osvvpjhMpeUlKTDhw9nKd5SpUopb968WrRokb777jvNnDnT6+Z9ycnJOnXqlHbv3q2wsDDPj0zZdeutt2rAgAGKi4tTp06dvK7XP9ehQ4ey1B9Fixa94F3Kz+fIkSPZ+mERAAIFdy8HgADVrVs37dq1S8uWLctw/A8//KDdu3d77hounT2CdvTo0XRt3Uc73WbPnq3ExER99dVXuuuuu9S5c2fFxsZ6nXJ+sc53JCqjuJKSkrR///5szy+rWrRooeLFi+uTTz7JUoFQsWLFDJ+HvWXLFs946X9HlM/N69zP+mL44mieO97t27enG5fRsKyqU6eOevXqpf/7v//Tnj17JElVqlSRmSkyMlKxsbHp/po2beo1jejoaD3xxBNaunSpfvjhB/3111+aMGGCpEv/fM/3WYaFhemOO+7QJ598or1796pOnTrnvRu69L8fb3bt2nXBeVepUsXz2WS0jC9fvlxlypTJ0p/7ru/uz7hHjx6KjIz0/P31119atGiRIiMj9cEHH1wwtgv5z3/+ozx58mjlypUXvGt5o0aNspTDpT5ne9euXdm+KSMABAKOdANAgHrooYc0depU3XXXXVq6dKnnSJskHT58WHfffbeCg4M1ePBgz/AqVaooPj5e69at85wuu3//fn3xxRde03YfhUx7NDQ+Pl6TJk3KdrxFihSRlL5Icse1dOlSr2HvvvvuJR+1zIrChQtr+PDhevTRRzV8+HC9/PLL6Qqyjz76SNWqVVPjxo3VuXNnjR07VitWrFBMTIwk6cSJE3r33XdVqVIlRUVFeXKSpKVLl6pevXqSzh6Ffffdd7Md6/k+w+wqW7asateurSlTpmjEiBGeI45LlizR+vXrPUV5djzyyCOaMmWKXnvtNY0dO1Y9evTQiBEjNGrUKH300Uden7OZ6fDhwypRooQSEhJUuHBhr+dBR0dHK0+ePEpMTJR09rKAkiVLaunSpRo2bJinXVbv1F+kSJEMP8d//vnHa10qWrSoqlatmu6RZudq0KCBChQooNWrV+vaa6+94Pzd13anfSycW3au6W7btm269ViSBg4cqIoVK+rxxx9XdHR0lqZ5PkWLFtX48eO1e/dudevW7bxtL8c13fHx8dqxY4fuueeebE8DAPyNohsAAlTVqlU1ZcoU3XLLLYqOjla/fv0UGRmp3bt36/3339eRI0c0ffp0RUZGet5z8803a/jw4frPf/6joUOH6uTJkxo/fryqVavmde1u+/btVaBAAXXr1k133XWXjh8/rokTJ6p06dLZPvpcr1495c2bVy+++KLi4+MVFBTkeQ54//79dffdd6tnz5665ppr9Ntvv2nu3LmX7ZTRhx9+WBs3btSrr76q77//Xtdff70iIiIUFxenWbNm6eeff9by5cslSY8++qjnsUlDhw5VWFiYPvzwQ+3atUuff/655/FNtWrVUtOmTTVixAgdPnxYYWFhmj59upKTk7MdZ5UqVRQaGqoJEyaoWLFiKlKkiJo0aeLVx9nx/PPPq3v37mrevLnuuOMOHTlyRG+//bZq166t48ePZ3u6UVFR6ty5s9577z09+eSTqlKlip599lmNGDFCu3fv1nXXXadixYpp165d+uKLLzRw4EA99NBDWrRokQYPHqwbbrhB1apVU3JysqZOnaq8efN6Xa/cv39/vfDCC+rfv78aNmyopUuX6vfff89SbA0aNND48eP17LPPqmrVqipdurTatm2rqKgotWnTRg0aNFBYWJhWr16tGTNmeP14lZGCBQuqffv2WrBggUaPHn3B+buPdn/44YfpxmXnmu4KFSpkeG+FYcOGKTw8PN1p7H379vUstxf7LPY+ffpkqV12r+mePXu2fvvtN0lnH5+2bt06Pfvss5LO3pwv7fX1CxYskJmpe/fu2ZoXAAQEP901HQCQRevXr7dbb73VIiIiLE+ePCbJChYsaBs3bsyw/bx586x27dpWoEABq169un300UcZPjLsq6++sjp16ljBggWtUqVK9uKLL9oHH3yQ7jFFmT2SqHXr1ukeyTRx4kSrXLmy5c2b1+uxWSkpKTZ8+HArWbKkFS5c2Dp06GDbt2/P9JFhq1at8pquO/5Dhw55De/Tp48VKVLkAp/g/8yYMcPat29vYWFhli9fPitTpozddNNNtnjxYq92O3bssOuvv95CQ0OtYMGC1rhxY5szZ0666e3YscNiY2MtKCjIwsPD7bHHHrP58+dn+MiwWrVqpXt/Ro94+/LLLy0qKsry5cvn9ciszB4Z9vLLL6eb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zDMaPny4Ro4cqQIFCvgjNQAAAAAAAuua7vj4eElSWFiYJGnNmjU6c+aMYmNjPW1q1KihChUqaMWKFZKkFStWKDo6WuHh4Z42HTp0UEJCgjZu3HgZowcAAAAAwJtfj3SnlZqaqmHDhql58+aqXbu2JCkuLk4FChRQaGioV9vw8HDFxcV52qQtuN3j3eMykpiYqMTERM/rhISEnEoDAAAAAACPbB3p/uWXX7R+/XrP6y+//FLXXXedHnvsMSUlJWUrkEGDBmnDhg2aPn16tt5/McaMGaOQkBDPX/ny5X0+TwAAAADAv0+2iu677rpLv//+uyRp586duvnmm1W4cGF99tlneuSRRy56eoMHD9acOXP0/fffq1y5cp7hERERSkpK0tGjR73aHzhwQBEREZ42597N3P3a3eZcI0aMUHx8vOdv7969Fx0zAAAAAAAXkq2i+/fff1e9evUkSZ999platWqladOmafLkyfr888+zPB0z0+DBg/XFF19o0aJFioyM9BrfoEED5c+fXwsXLvQM27p1q/bs2aOYmBhJUkxMjNavX6+DBw962syfP1/BwcGKiorKcL5BQUEKDg72+gMAAAAAIKdl65puM1NqaqokacGCBerataskqXz58vr777+zPJ1BgwZp2rRp+vLLL1WsWDHPNdghISEqVKiQQkJC1K9fPz3wwAMKCwtTcHCwhgwZopiYGDVt2lSS1L59e0VFRen222/XSy+9pLi4OD3xxBMaNGiQgoKCspMeAAAAAAA5IltFd8OGDfXss88qNjZWS5Ys0fjx4yVJu3btSndTs/Nxv69NmzZewydNmqS+fftKkl5//XXlyZNHPXv2VGJiojp06KB33nnH0zZv3ryaM2eO7rnnHsXExKhIkSLq06ePRo8enZ3UAAAAAADIMdkqul9//XX16tVLs2bN0uOPP66qVatKkmbMmKFmzZpleTpmdsE2BQsW1Lhx4zRu3LhM21SsWFHffPNNlucLAAAAAMDlkK2iu27dul53L3d7+eWXlS9fwDyFDAAAAAAAv8rWjdQqV66sf/75J93w06dPq1q1apccFAAAAAAATpCtonv37t1KSUlJNzwxMVF//vnnJQcFAAAAAIATXNS54F999ZXn/3PnzlVISIjndUpKihYuXJjusV8AAAAAAPxbXVTRfd1110mSXC6X+vTp4zUuf/78qlSpkl599dUcCw4AAAAAgNzsoopu97O5IyMjtWrVKpUsWdInQQEAAAAA4ATZutX4rl27cjoOAAAAAAAcJ9vP91q4cKEWLlyogwcPeo6Au33wwQeXHBgAAAAAALldtoruUaNGafTo0WrYsKHKlCkjl8uV03EBAAAAAJDrZavonjBhgiZPnqzbb789p+MBAAAAAMAxsvWc7qSkJDVr1iynYwEAAAAAwFGyVXT3799f06ZNy+lYAAAAAABwlGydXn769Gm9++67WrBggerUqaP8+fN7jX/ttddyJDgAAAAAAHKzbBXd69atU7169SRJGzZs8BrHTdUAAAAAADgrW0X3999/n9NxAAAAAADgONm6phsAAAAAAFxYto50X3311ec9jXzRokXZDggAAAAAAKfIVtHtvp7b7cyZM1q7dq02bNigPn365ERcAAAAAADketkqul9//fUMh48cOVLHjx+/pIAAAAAAAHCKHL2mu1evXvrggw9ycpIAAAAAAORaOVp0r1ixQgULFszJSQIAAAAAkGtl6/TyHj16eL02M+3fv1+rV6/Wk08+mSOBAQAAAACQ22Wr6A4JCfF6nSdPHlWvXl2jR49W+/btcyQwAAAAAAByu2wV3ZMmTcrpOAAAAAAAcJxsFd1ua9as0ebNmyVJtWrVUv369XMkKAAAAAAAnCBbRffBgwd18803a/HixQoNDZUkHT16VFdffbWmT5+uUqVK5WSMAAAAAADkStm6e/mQIUN07Ngxbdy4UYcPH9bhw4e1YcMGJSQkaOjQoTkdIwAAAAAAuVK2jnR/9913WrBggWrWrOkZFhUVpXHjxnEjNQAAAAAA/r9sHelOTU1V/vz50w3Pnz+/UlNTLzkoAAAAAACcIFtFd9u2bXXfffdp3759nmF//fWX7r//frVr1y7HggMAAAAAIDfLVtH99ttvKyEhQZUqVVKVKlVUpUoVRUZGKiEhQW+99VZOxwgAAAAAQK6UrWu6y5cvr19++UULFizQli1bJEk1a9ZUbGxsjgYHAAAAAEBudlFHuhctWqSoqCglJCTI5XLpmmuu0ZAhQzRkyBA1atRItWrV0g8//OCrWAEAAAAAyFUuqugeO3asBgwYoODg4HTjQkJCdNddd+m1117LseAAAAAAAMjNLqro/u2339SxY8dMx7dv315r1qy55KAAAAAAAHCCiyq6Dxw4kOGj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U7FixRQRESEpdy13HTp0cMxy57T1SHLe9jtPnjxq3769br/9dlWsWNGzzkjSkiVL1KFDB6WkpChPnjwBn48Tvzc4MSfJWfskN6fl5LRtneTMfdJF82/Nj0Cyd+9ez69M5/u1dubMmRYSEmLr1q0zs8D+Reqff/7x5HK+OD/55BMrVqyYbd68+YJt/enbb7+1UaNG2SOPPGKff/55pnHmpj768ccfbcaMGTZlyhTbu3dvpu0mTZpkRYoUse3bt1/G6C7eokWLbPz48fbKK6/Yzz//nOlnn1uWOTOzLVu22PHjx83s/NuGr7/+2kqWLGmrVq0ys8DOyX1E0ez8ceaW5c5p65GZ87bfa9asse+//96+/vprr+XvXOPHj7dixYrZH3/8cRmjyx4nfm9wWk5O3Cc5LSenbevMnLlPulQU3TAzs48++shq165tH330kSUmJppZ+pU5NTXVUlJS7P7777d7773XkpKSAvpUqqlTp1rLli1t+fLlmW6YUlNT7dSpUzZw4EB76KGHzCxwTw+bNGmSFSpUyG666SarXr261apVy9q0aeP58pacnJzr+ui9996z4OBga9KkieXPn98aNWpkTz/9tKe/3DklJCRYr1697MknnzSzwO2j999/34oWLWrt27e3sLAwq1u3rvXt29cTrzuf3LLMmZ3dNlxxxRX2zDPP2LFjx8ws8x39E088YX379rWEhISA/jIwZcoU6969u+eU0IzkpuXOaeuRmfO23xMnTrQSJUpYrVq1zOVyWZs2beyDDz7wjE9JSbHU1FQ7dOiQ9ejRw8aMGeMZHqic+L3BaTk5cZ/ktJyctq0zc+Y+KSdQdMPmzZtn5cqVs3Llylnjxo3t008/zXRnExcXZ+XKlbP333/fH6Fm2bfffmulS5e2ggUL2lVXXXXeX0J37dplZcuW9bpmJtDs37/fatasaePHjzczs9OnT9vs2bMtOjraatWq5TkKaZZ7+mjjxo12xRVX2LRp0+z06dN25MgRu++++6xBgwZ25513evXXhg0brGzZsjZ79mw/Rnx+O3futMjISJs8ebKZmR0/ftzeeOMNq1OnjrVr185rZ5Ibljkzs4ULF1pkZKTVrVvXmjVrZi+88EKmhffhw4etUqVK9uabb/oj1CybM2eOBQcHm8vlsvbt21tcXFymbXPDcue09cjMedvvVatWWenSpe3TTz+1AwcO2B9//GHXXnutNW3a1EaPHu2V208//WRly5a1hQsX+jHiC3Pi9wan5eTEfZLTcnLats7MmfuknBL4F5/Ap06dOqVly5apY8eO+vHHH1W6dGmNGTNGs2bNUlJSklwul8zMq/1zzz2nO++8049Rn198fLzmz5+vW265RTt27NCZM2d05513avXq1Z5c0uaUkJCghx9+WDfddJO/Qr6gU6dOKT4+XvXr15ckBQUFqVOnTpo6dary5s2rtm3benI6efJkwPeRJB04cEAul0utWrVSUFCQQkNDNWrUKN1222369ddf9dBDD3naHj58WP3791fXrl39GPH5HT16VKdOnVKTJk0kSUWKFNGAAQM0atQoxcXF6cYbb/T0UXx8fMAvcykpKVqzZo2aNWumL774QldddZVmzJihcePG6fjx43K5XJ5nbUpn16lx48ZpyJAhnteB5tChQ5o1a5buvPNO/fzzz/r99991yy236MCBAxm2zw3LndPWIyduv/fs2aOQkBB16NBBpUuXVoUKFfT++++rUaNGmjNnjt566y1P24MHD+r6669X27Zt/Rjx+Tnxe4MTc3LaPklyVk5O3NZJztsn5Sg/FPoIIKmpqbZ27Vr74YcfzOzsKR9dunSxevXq2aeffuq5rimtEydOeN4biJKSkmzevHm2ZMkSMzt7x8TatWtb7dq17eeff87w9JWTJ0+aWeDmlJiYaDVr1rQRI0akG7dkyRKLioqyZ5991qu9WeDmY2a2du1aq1y5sn377bdm9r9Yjx07ZiNHjrQGDRp4+tAs8HPat2+fVa1a1SZMmOA1PDEx0T788EOrW7euTZ061Wu4WeDmY3b2DIsff/zRzM7Gee+991rDhg3thRdesISEhHTt3etRoDp58qRNnTrVs73btm2bVaxY0a6++upMj3i7L98I1H5y2nqUlJRkc+fOddT2+9tvv7XIyEjbsGGDmZ3NyezsdZx9+vSx5s2be13PmJSUZGaBm48Tvzc4Maf9+/dblSpVHLdPckpOTtzWmTlvn5STKLrh+QLgXuDPnDnjtbM5c+aMxcfH29tvv+3PMLMkbQ5m/7s+JCkpybMxc9/k6ejRo/bpp5/6J9CLkJqaasnJyfbwww9by5YtvR7P5B5/++23W5cuXXLVRuuff/6xBg0a2PXXX2///POP17gTJ05Y5cqV7ZFHHvFTdBcvISHBevbsaR06dLD169d7jUtKSrJWrVpZ3759/RTdxclsOUpOTvYqvE+cOGHHjh3zulYr0J17A6vff//dU3gfOHDAzMyOHDliixYt8kd4F+3QoUN21VVXOWY9MvvflzAnbL/NzP78808LDw+3wYMHe4YlJyebmdnff/9tISEh9vLLL/srvIviXs/P/dcJ3xuclJPZ2fX/+uuvd8Q+yc1pOTltW2fmzH1STqHo/hdau3atff311/bDDz94ju6cW6wmJSVZly5drH79+jZx4kSLiYmxxo0bB+xNDjL6FdrNnVNiYqLVrl3boqOj7bvvvrOYmBjr1KlTQBYL8fHxnv+749u9e7c1bdrU2rdvb/PmzfNq//rrr1urVq0C+khj2j5yL0erV6+2oKAgu/fee9MdOb3zzjvtzjvvvKwxXoy065H7hlwbN2608PBw6969u23ZssWr/YgRI6x79+6eL9uBKO1ydy533GfOnLFBgwZZ48aN7cknn7SYmBirUqVKwOa1Z88e27Rpkx09etRTcLtvWuW2detWq1ixorVt29bWr19vTZs2tdtuuy0gtw1bt261H3/80bZv326HDx82M7OVK1dagQIF7J577sl165HZ/3Latm2b59mz7m1Ebtx+p13m3EdDZ86caXnz5vU6I8kde9euXQP+S6g7j4y41/3c9r3BaTmlzccd35YtWyw8PNyuu+66XLlPclpOTtvWmTlzn+QrFN3/MhMnTrSIiAiLjIy0ihUrWtWqVe3777/3apP2KHGHDh3M5XJZnTp1AvaUty+//NKee+65894QyR17cnKy5+6xtWrVCsicPv30U2vXrp3XY5fcO5AtW7bYVVddZbGxsfbWW29ZYmKi7d+/39q1a2e33367P8M+r4z6yJ3T7NmzLSgoyHr16mW//fabpaam2smTJ61x48Y2fPhwf4V8XhmtR/Pnzzezs8V4aGiodevWzb766itLTk62I0eOWMuWLe2ee+7xc+SZO3e5y4i7z1JTU61fv37mcrnsqquu8qxHgfZF9IMPPrCqVataRESEValSxQYMGGC///67mXnnYma2fft2q1SpkrlcLqtRo4Ynp0Dy3nvvWfny5a1s2bJWqVIla9u2rf3yyy9mZjZr1iwrUKBArlqPzNLn1K5dO88jmNIe/THLHdvvtMtc1apVrX///rZ161YzMxs7dqzl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Q4cO1SOPPKKwsDBFRERo5MiRnvGVKlWSJP3nP/+Ry+XyvD739HL3vF555RWVKVNGJUqU0KBBg3TmzBlPm/3796tLly4qVKiQIiMjNW3aNFWqVEljx4497+eRL18+RURE6IorrlBsbKxuuOEGzZ8/36vNe++9p5o1a6pgwYKqUaOG3nnnHa/xy5cvV7169VSwYEE1bNhQs2bNksvl0tq1ayWlP3r9xx9/qFu3bipevLiKFCmiWrVq6ZtvvtHu3bt19dVXS5KKFy8ul8ulvn37SpJSU1M1ZswYRUZGqlChQqpbt65mzJjhicE9j2+//VYNGjRQUFCQli1blmneffr00fTp03Xq1CnPsA8++EB9+vRJ13bv3r268cYbFRoaqrCwMHXv3l27d+/2jF+1apWuueYalSxZUiEhIWrdurV++eUXz3gz08iRI1WhQgUFBQWpbNmyGjp0qGd8Rmc7hIaGavLkyZLO/lDkcrn06aefqnXr1ipYsKA+/vjjC/aN+33//e9/1bJlSxUqVEiNGjXS77//rlWrVqlhw4YqWrSoOnXqpEOHDnnNPyvTnTlzpq6++moVLlxYdevW1YoVKzx9cccddyg+Pt5zVkHa5R4A4CcGAICP/fPPP+Zyuez5558/b7uUlBSrV6+etWjRwlavXm0rV660Bg0aWOvWrT1t+vTpY927d/d633333efVpnXr1hYcHGwjR46033//3T788ENzuVw2b948MzM7ePCgSbJJkybZ/v377eDBg2Zm9vTTT1vdunW95hUcHGx33323bd682WbPnm2FCxe2d99919MmNjbW6tWrZytXrrQ1a9ZY69atrVChQvb6669nmue589m1a5fVqlXLwsPDPcM++ugjK1OmjH3++ee2c+dO+/zzzy0sLMwmT55sZmbx8fEWFhZmvXr1so0bN9o333xj1apVM0n266+/mpnZ999/b5LsyJEjZmbWpUsXu+aaa2zdunW2Y8cOmz17ti1ZssSSk5Pt888/N0m2detW279/vx09etTMzJ599lmrUaOGfffdd7Zjxw6bNGmSBQUF2eLFi73mUadOHZs3b55t377d/vnnnwzzlmRffPGF1alTx6ZOnWpmZn/88YcFBQXZ77//bpLs+++/NzOzpKQkq1mzpt155522bt0627Rpk916661WvXp1S0xMNDOzhQsX2tSpU23z5s22adMm69evn4WHh1tCQoKZmX322WcWHBxs33zzjf3xxx/2008/efWdO560QkJCbNKkSZ5+kWSVKlXy9MO+ffsu2Dfu97k/t02bNlnTpk2tQYMG1qZNG1u2bJn98ssvVrVqVbv77ruz3OdppztnzhzbunWrXX/99VaxYkU7c+aMJSYm2tixYy04ONj2799v+/fvt2PHjmW6HAIALg+KbgCAz/30008myWbOnHnedvPmzbO8efPanj17PMM2btxokuznn382s6wX3S1atPBq06hRIxs+fLjndUYFV0ZFd8WKFS05Odkz7IYbbrCbbrrJzMw2b95skmzVqlWe8du2bTNJFyy68+TJY0WKFLGCBQuaJJNkr732mqdNlSpVbNq0aV7ve+aZZywmJsbMzMaPH28lSpSwU6dOecZPnDjxvEV3dHS0jRw5MsOYzm1rZnb69GkrXLiwLV++3Kttv3797JZbbvF636xZszLN1839mY8dO9auvvpqMzMbNWqU/ec//7EjR454Fd1Tp0616tWrW2pqquf9iYmJVqhQIZs7d26G009JSbFixYrZ7Nmzzczs1VdftWrVqllSUtJ540kro6J77NixXm0u1Dfu97333nue8Z988olJsoULF3qGjRkzxqpXr35J03WvH5s3bzYzs0mTJllISEiG+QIA/INrugEAPmdmWWq3efNmlS9fXuXLl/cMi4qKUmhoqDZv3qxGjRpleZ516tTxel2mTBkdPHgwy+93q1WrlvLmzes1nfXr10uStm7dqnz58umqq67yjK9ataqKFy9+welWr15dX331lU6fPq2PPvpIa9eu1ZAhQyRJJ06c0I4dO9SvXz8NGDDA857k5GTPTdG2bt2qOnXqqGDBgp7xjRs3Pu88hw4dqnvuuUfz5s1TbGysevbsme5zSmv79u06efKkrrnmGq/hSUlJql+/vtewhg0bXjBnt169eunRRx/Vzp07NXnyZL355pvp2vz222/avn27ihUr5jX89OnT2rFjhyTpwIEDeuKJJ7R48WIdPHhQKSkpOnnypPbs2SNJuuGGGzR27FhVrlxZHTt2VOfOndWtW7dMrzfPTNrcstI3bmk/2/DwcElSdHS01zD3Mpnd6ZYpU0aSdPDgQdWoUeOi8gIAXB4U3QAAn7vyyivlcrly5GZpefLkSVfEp73G2u3cm125XC6lpqZe9PxyajrnKlCggKpWrSpJeuGFF9SlSxeNGjVKzzzzjI4fPy5Jmjhxopo0aeL1vrQ/AFys/v37q0OHDvr66681b948jRkzRq+++qqn2D+XO46vv/5aV1xxhde4oKAgr9dFihTJchwlSpRQ165d1a9fP50+fVqdOnXSsWPH0s27QYMGnmuo0ypVqpSks9eH//PPP3rjjTdUsWJFBQUFKSYmRklJSZLO3rRt69atWrBggebPn697771XL7/8spYsWaL8+fPL5XJlaVlKm9vF9E3aZcflcmU4zL0sXep0c2KZBAD4BjdSAwD4XFhYmDp06KBx48bpxIkT6ca7b/RVs2ZN7d27V3v37vWM27Rpk44ePaqoqChJZwuu/fv3e73ffeOwi5E/f36lpKRc9PvSql69upKTk/Xrr796hm3fvl1Hjhy56Gk98cQTeuWVV7Rv3z6Fh4erbNmy2rlzp6pWrer1FxkZ6Zn3+vXrlZiY6JnGqlWrLjif8uXL6+6779bMmTP14IMPauLEiZLO/gggyesziYqKUlBQkPbs2ZMujrRnI2THnXfeqcWLF6t3794Z/pBw1VVXadu2bSpdunS6ebuP/P74448aOnSoOnfurFq1aikoKEh///2313QKFSqkbt266c0339TixYu1YsUKz5kK5y5L27Zt08mTJ88bd1b6JjtyaroFChS45OUaAJCzKLoBAJfFuHHjlJKSosaNG+vzzz/Xtm3btHnzZr355puKiYmRJMXGxio6Olq33XabfvnlF/3888/q3bu3Wrdu7TnFt23btlq9erWmTJmibdu26emnn9aGDRsuOp5KlSpp4cKFiouLy1aRLEk1atRQbGysBg4cqJ9//lm//vqrBg4cqEKFCnmOQGZVTEyM6tSpo+eff16SNGrUKI0ZM0Zvvvmmfv/9d61fv16TJk3Sa6+9Jkm69dZblZqaqoEDB2rz5s2aO3euXnnlFUnKdN7Dhg3T3LlztWvXLv3yyy/6/vvvVbNmTUlSxYoV5XK5NGfOHB06dEjHjx9XsWLF9NBDD+n+++/Xhx9+qB07duiXX37RW2+9pQ8//DBbn5lbx44ddejQIY0ePTrD8bfddptKliyp7t2764cfftCuXbu0ePFiDR06VH/++aeks2dQTJ06VZs3b9ZPP/2k2267TYUKFfJMY/LkyXr//fe1YcMG7dy5Ux999JEKFSqkihUrSjq7LL399tv69ddftXr1at19991ZehzYhfomu3JiupUqVdLx48e1cOFC/f333xf8EQEA4HsU3QCAy6Jy5cr65ZdfdPXVV+vBBx9U7dq1dc0112jhwoUaP368pLPF4pdffqnixYurVatWio2NVeXKlb2eXd2hQwc9+eSTeuSRR9SoUSMdO3ZMvXv3vuh4Xn31Vc2fP1/ly5dPd33yxZgyZYrCw8PVqlUr/ec//9GAAQNUrFgxr2uts+r+++/Xe++9p71796p///567733NGnSJEVHR6t169aaPHmy56hncHCwZs+erbVr16pevXp6/PHH9dRTT0lSpvNOSUnRoEGDVLNmTXXs2FHVqlXzPJLqiiuu0KhRo/Too48qPDxcgwcPliQ988wzevLJJzVmzBjP+77++utLOqorne3rkiVLeo6wn6tw4cJaunSpKlSooB49eqhmzZqe09GDg4MlSe+//76OHDmiq666SrfffruGDh2q0qVLe6YRGhqqiRMnqnnz5qpTp44WLFig2bNnq0SJEpLOLgPly5dXy5Ytdeutt+qhhx5S4cKFLxj7hfomu3Jius2aNdPdd9+tm266SaVKldJLL710STEBAC6dy7J6dxsAAHBBf/75p8qXL68FCxaoXbt2l3XeH3/8sec5zWmP+AIAAP/hRmoAAFyCRYsW6fjx44qOjtb+/fv1yCOPqFKlSmrVqpXP5z1lyhRVrlxZV1xxhX777TcNHz5cN954IwU3AAABhKIbAIBLcObMGT322GPauXOnihUrpmbNmunjjz/O0rXBlyouLk5PPfWU4uLiVKZMGd1www167rnnfD5fAACQdZxeDgAAAACAj3AjNQAAAAAAfISiGwAAAAAAH6HoBgAAAADARyi6AQAAAADwEYpuAAAAAAB8hKIbAAAAAAAfoegGAAAAAMBHKLoBAAAAAPARim4AAAAAAHzk/wEdEXhdX/8QugAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Visualize counting register results\n", + "counting_results = results['counting_register_results']\n", + "sorted_results = sorted(counting_results.items(), key=lambda x: x[1], reverse=True)\n", + "\n", + "labels = [f\"|{bs}>\" for bs, _ in sorted_results]\n", + "values = [c for _, c in sorted_results]\n", + "\n", + "plt.figure(figsize=(10, 5))\n", + "plt.bar(labels, values, color='steelblue', alpha=0.8)\n", + "plt.xlabel('Counting Register Measurement')\n", + "plt.ylabel('Counts')\n", + "plt.title(f'Quantum Counting Results (N={N}, M={len(marked_states)})')\n", + "plt.xticks(rotation=45)\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 2: Counting Multiple Marked Items\n", + "\n", + "Count 2 marked items in an 8-element search space ($N = 8$, $n = 3$)." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Quantum Counting Results (N=8, M=2):\n", + "Measurement counts: Counter({'11011101': 184, '00101010': 178, '00101101': 173, '11011010': 167, '11011011': 62, '00101000': 61, '11011110': 59, '00101111': 57, '11011100': 57, '00101001': 55, '11011000': 55, '00101110': 53, '11011001': 47, '00101011': 47, '11011111': 46, '11010101': 44, '00101100': 42, '00110101': 41, '11010010': 37, '00110010': 34, '00110000': 18, '11010000': 18, '00110100': 18, '11010111': 18, '00100101': 17, '00110110': 16, '11010110': 15, '11100101': 15, '11010001': 15, '00100010': 14, '00110001': 13, '11100010': 13, '00110111': 13, '11010100': 12, '11010011': 9, '00110011': 9, '00011010': 9, '00111010': 8, '11100111': 8, '11001001': 7, '11001101': 7, '11001100': 6, '11001010': 6, '00111001': 6, '00100100': 6, '00100001': 6, '11100000': 5, '11100011': 5, '00111111': 5, '01000101': 5, '00100110': 4, '00010101': 4, '11110010': 4, '00010010': 4, '11111010': 4, '11100100': 4, '11001011': 4, '11000010': 4, '00111101': 4, '00011101': 4, '01000000': 3, '01001001': 3, '11101010': 3, '10010000': 3, '00100111': 3, '01000010': 3, '00111110': 3, '01100001': 2, '11101101': 2, '01011111': 2, '11000101': 2, '01111001': 2, '01001101': 2, '01000111': 2, '00011001': 2, '11001000': 2, '11101111': 2, '11100110': 2, '01011101': 2, '00000110': 2, '00111011': 2, '01011010': 2, '00011110': 2, '11101110': 2, '01000100': 2, '10101110': 2, '00000010': 2, '11000000': 2, '00111100': 2, '01001010': 2, '00000101': 2, '00001101': 2, '01010011': 2, '00100000': 2, '00111000': 2, '11101001': 2, '11001111': 2, '01111011': 1, '10011001': 1, '10001110': 1, '11101011': 1, '01111110': 1, '10110001': 1, '11100001': 1, '11000111': 1, '11000001': 1, '10101011': 1, '00001111': 1, '01100101': 1, '11000011': 1, '01111010': 1, '10101111': 1, '10001010': 1, '10011101': 1, '01011000': 1, '11110100': 1, '10011000': 1, '01101011': 1, '01101001': 1, '10110011': 1, '01001011': 1, '01001100': 1, '10111100': 1, '00010111': 1, '00010001': 1, '11110011': 1, '01000011': 1, '10111101': 1, '00001000': 1, '11111101': 1, '00001010': 1, '00001100': 1, '10100100': 1, '01000110': 1, '10011100': 1, '11111110': 1, '01001111': 1, '11000100': 1, '10011011': 1, '00011000': 1, '10101001': 1, '11110111': 1, '00000011': 1, '11101000': 1, '01110110': 1, '11001110': 1, '11110101': 1, '10111110': 1, '11000110': 1, '00011100': 1, '10111000': 1, '01000001': 1, '10111010': 1, '01100110': 1, '01101000': 1})\n", + "Counting register results: {'11010': 168, '00101': 666, '00110': 162, '01100': 4, '11100': 53, '11011': 677, '00100': 52, '01111': 5, '11001': 35, '10011': 5, '10001': 2, '11101': 13, '00010': 10, '11110': 8, '01011': 7, '11000': 13, '00111': 32, '10110': 2, '01001': 10, '01000': 18, '00011': 19, '11111': 6, '10101': 5, '00001': 6, '00000': 7, '10010': 3, '01101': 3, '01010': 2, '10111': 5, '10100': 1, '01110': 1}\n", + "Phase estimates: [0.8125, 0.15625, 0.1875, 0.375, 0.875, 0.84375, 0.125, 0.46875, 0.78125, 0.59375, 0.53125, 0.90625, 0.0625, 0.9375, 0.34375, 0.75, 0.21875, 0.6875, 0.28125, 0.25, 0.09375, 0.96875, 0.65625, 0.03125, 0.0, 0.5625, 0.40625, 0.3125, 0.71875, 0.625, 0.4375]\n", + "Estimated item counts: [np.float64(2.4692662705396407), np.float64(1.777719067921591), np.float64(2.4692662705396407), np.float64(6.82842712474619), np.float64(1.1715728752538106), np.float64(1.7777190679215926), np.float64(1.17157287525381), np.float64(7.923141121612921), np.float64(3.219638711935487), np.float64(7.325878449210182), np.float64(7.923141121612923), np.float64(0.6741215507898192), np.float64(0.30448186995485294), np.float64(0.30448186995485405), np.float64(6.222280932078408), np.float64(4.000000000000001), np.float64(3.219638711935487), np.float64(5.530733729460362), np.float64(4.780361288064514), np.float64(3.999999999999999), np.float64(0.6741215507898188), np.float64(0.07685887838707856), np.float64(6.22228093207841), np.float64(0.07685887838707821), np.float64(0.0), np.float64(7.695518130045147), np.float64(7.325878449210182), np.float64(5.530733729460359), np.float64(4.7803612880645145), np.float64(6.82842712474619), np.float64(7.695518130045147)]\n", + "Best estimate of M: 1.7777190679215926\n", + "Search space size N: 8\n", + "\n", + "Actual M = 2\n", + "Estimated M ≈ 1.7777\n" + ] + } + ], + "source": [ + "n_counting = 5\n", + "n_search = 3\n", + "marked_states = [2, 5]\n", + "N = 2**n_search\n", + "\n", + "counting_qubits = list(range(n_counting))\n", + "search_qubits = list(range(n_counting, n_counting + n_search))\n", + "\n", + "grover = build_grover_matrix(n_search, marked_states)\n", + "circ = Circuit()\n", + "circ = quantum_counting_circuit(circ, counting_qubits, search_qubits, grover)\n", + "\n", + "device = LocalSimulator()\n", + "task = run_quantum_counting(circ, device, shots=2000)\n", + "\n", + "print(\"Quantum Counting Results (N=8, M=2):\")\n", + "results = get_quantum_counting_results(\n", + " task, counting_qubits, search_qubits, verbose=True\n", + ")\n", + "\n", + "print(f\"\\nActual M = {len(marked_states)}\")\n", + "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 3: Edge Case — No Marked Items (M = 0)\n", + "\n", + "When no items are marked, the algorithm should estimate $M \\approx 0$." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Measurement counts: Counter({'000011': 255, '000000': 252, '000010': 249, '000001': 244})\n", + "Counting register results: {'0000': 1000}\n", + "Phase estimates: [0.0]\n", + "Estimated item counts: [np.float64(0.0)]\n", + "Best estimate of M: 0.0\n", + "Search space size N: 4\n", + "\n", + "Actual M = 0\n", + "Estimated M ≈ 0.0000\n" + ] + } + ], + "source": [ + "n_counting = 4\n", + "n_search = 2\n", + "marked_states = []\n", + "N = 2**n_search\n", + "\n", + "counting_qubits = list(range(n_counting))\n", + "search_qubits = list(range(n_counting, n_counting + n_search))\n", + "\n", + "grover = build_grover_matrix(n_search, marked_states)\n", + "circ = Circuit()\n", + "circ = quantum_counting_circuit(circ, counting_qubits, search_qubits, grover)\n", + "\n", + "device = LocalSimulator()\n", + "task = run_quantum_counting(circ, device, shots=1000)\n", + "\n", + "results = get_quantum_counting_results(\n", + " task, counting_qubits, search_qubits, verbose=True\n", + ")\n", + "\n", + "print(f\"\\nActual M = 0\")\n", + "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 4: Edge Case — All Items Marked (M = N)\n", + "\n", + "When all items are marked, $M = N$." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Measurement counts: Counter({'100011': 278, '100010': 251, '100001': 243, '100000': 228})\n", + "Counting register results: {'1000': 1000}\n", + "Phase estimates: [0.5]\n", + "Estimated item counts: [np.float64(4.0)]\n", + "Best estimate of M: 4.0\n", + "Search space size N: 4\n", + "\n", + "Actual M = 4\n", + "Estimated M ≈ 4.0000\n" + ] + } + ], + "source": [ + "n_counting = 4\n", + "n_search = 2\n", + "N = 2**n_search\n", + "marked_states = list(range(N))\n", + "\n", + "counting_qubits = list(range(n_counting))\n", + "search_qubits = list(range(n_counting, n_counting + n_search))\n", + "\n", + "grover = build_grover_matrix(n_search, marked_states)\n", + "circ = Circuit()\n", + "circ = quantum_counting_circuit(circ, counting_qubits, search_qubits, grover)\n", + "\n", + "device = LocalSimulator()\n", + "task = run_quantum_counting(circ, device, shots=1000)\n", + "\n", + "results = get_quantum_counting_results(\n", + " task, counting_qubits, search_qubits, verbose=True\n", + ")\n", + "\n", + "print(f\"\\nActual M = {N}\")\n", + "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## [Optional] Run on a QPU or Managed Simulator\n", + "\n", + "[Include estimated price for running in USD using the [cost tracker](https://docs.aws.amazon.com/braket/latest/developerguide/braket-pricing.html#real-time-cost-tracking).]" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# Use Braket SDK Cost Tracking to estimate the cost to run this example\n", + "# from braket.tracking import Tracker\n", + "\n", + "# tracker = Tracker().start()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# from braket.aws import AwsDevice, AwsSession\n", + "# import boto3\n", + "\n", + "# boto_session = boto3.Session(region_name=\"us-east-1\")\n", + "# aws_session = AwsSession(boto_session=boto_session)\n", + "\n", + "# # Run on managed simulator\n", + "# managed_device = AwsDevice(\n", + "# \"arn:aws:braket:::device/quantum-simulator/amazon/sv1\",\n", + "# aws_session=aws_session\n", + "# )\n", + "# n_counting = 4\n", + "# n_search = 2\n", + "# marked_states = [3]\n", + "# counting_qubits = list(range(n_counting))\n", + "# search_qubits = list(range(n_counting, n_counting + n_search))\n", + "# grover = build_grover_matrix(n_search, marked_states)\n", + "\n", + "# circ = Circuit()\n", + "# circ = quantum_counting_circuit(circ, counting_qubits, search_qubits, grover)\n", + "\n", + "# task = run_quantum_counting(circ, managed_device, shots=1000)\n", + "\n", + "# results = get_quantum_counting_results(\n", + "# task, counting_qubits, search_qubits, verbose=True\n", + "# )\n", + "# print(f\"\\nEstimated M ≈ {results['best_estimate']:.4f}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# print(\"Task Summary\")\n", + "# print(f\"{tracker.quantum_tasks_statistics()} \\n\")\n", + "# print(\n", + "# f\"Estimated cost to run this example: {tracker.qpu_tasks_cost() + tracker.simulator_tasks_cost():.2f} USD\"\n", + "# )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note: Charges shown are estimates based on your Amazon Braket simulator and quantum processing unit (QPU) task usage. Estimated charges shown may differ from your actual charges. Estimated charges do not factor in any discounts or credits, and you may experience additional charges based on your use of other services such as Amazon Elastic Compute Cloud (Amazon EC2)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/src/braket/experimental/algorithms/quantum_counting/__init__.py b/src/braket/experimental/algorithms/quantum_counting/__init__.py new file mode 100644 index 00000000..561b5e47 --- /dev/null +++ b/src/braket/experimental/algorithms/quantum_counting/__init__.py @@ -0,0 +1,21 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. + +from braket.experimental.algorithms.quantum_counting.quantum_counting import ( # noqa: F401, E501 + build_diffusion_matrix, + build_grover_matrix, + build_oracle_matrix, + get_quantum_counting_results, + quantum_counting_circuit, + run_quantum_counting, +) diff --git a/src/braket/experimental/algorithms/quantum_counting/quantum_counting.md b/src/braket/experimental/algorithms/quantum_counting/quantum_counting.md new file mode 100644 index 00000000..9a78a589 --- /dev/null +++ b/src/braket/experimental/algorithms/quantum_counting/quantum_counting.md @@ -0,0 +1,7 @@ +The Quantum Counting algorithm, introduced by Brassard, Høyer, and Tapp (1998), solves a generalization of the quantum search problem. Instead of merely detecting whether a marked item exists in an unstructured database of N elements, quantum counting determines the number of marked items M. The algorithm combines Grover's search operator with Quantum Phase Estimation (QPE): it prepares the Grover operator G = D·O (oracle followed by diffusion), whose eigenvalues encode θ such that M = N·sin²(θ/2), then uses QPE to estimate θ with t precision qubits. The algorithm achieves a quadratic speedup over classical counting, requiring only O(√N) oracle queries instead of the classical Θ(N). + + diff --git a/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py b/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py new file mode 100644 index 00000000..f72d1633 --- /dev/null +++ b/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py @@ -0,0 +1,345 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. + +"""Quantum Counting Algorithm implementation using the Amazon Braket SDK. + +The quantum counting algorithm combines Grover's search operator with Quantum +Phase Estimation (QPE) to count the number of marked items in an unstructured +search space of N = 2^n elements. + +Reference: + G. Brassard, P. Høyer, and A. Tapp, "Quantum Counting", + Proceedings of ICALP 1998. arXiv:quant-ph/9805082 +""" + +import math +from typing import Any, Dict, List, Tuple + +import numpy as np + +from braket.circuits import Circuit, circuit +from braket.circuits.qubit_set import QubitSetInput +from braket.devices import Device +from braket.tasks import QuantumTask + + + +def build_oracle_matrix(n_qubits: int, marked_states: List[int]) -> np.ndarray: + """Build a diagonal oracle matrix that flips the phase of marked states. + + The oracle acts as O|x> = -|x> for marked x, and O|x> = |x> otherwise. + + Args: + n_qubits (int): Number of qubits in the search register. + marked_states (List[int]): Indices of marked computational-basis states. + + Returns: + np.ndarray: The 2^n × 2^n diagonal oracle matrix. + + Raises: + ValueError: If a marked state index is out of range. + """ + dim = 2**n_qubits + oracle = np.eye(dim) + for state in marked_states: + if state < 0 or state >= dim: + raise ValueError( + f"Marked state {state} is out of range for {n_qubits} qubits " + f"(must be in [0, {dim - 1}])." + ) + oracle[state, state] = -1 + return oracle + + +def build_diffusion_matrix(n_qubits: int) -> np.ndarray: + """Build the Grover diffusion matrix D = 2|s> = H^{⊗n}|0>^{⊗n} is the uniform superposition state. + + Args: + n_qubits (int): Number of qubits in the search register. + + Returns: + np.ndarray: The 2^n × 2^n diffusion matrix. + """ + dim = 2**n_qubits + s = np.ones(dim) / np.sqrt(dim) + return 2 * np.outer(s, s) - np.eye(dim) + + +def build_grover_matrix(n_qubits: int, marked_states: List[int]) -> np.ndarray: + """Build the Grover operator G = D · O. + + Args: + n_qubits (int): Number of qubits in the search register. + marked_states (List[int]): Indices of marked states. + + Returns: + np.ndarray: The 2^n × 2^n Grover operator matrix. + """ + oracle = build_oracle_matrix(n_qubits, marked_states) + diffusion = build_diffusion_matrix(n_qubits) + return diffusion @ oracle + + +@circuit.subroutine(register=True) +def inverse_qft_for_counting(qubits: QubitSetInput) -> Circuit: + """Inverse Quantum Fourier Transform applied to the given qubits. + + Args: + qubits (QubitSetInput): Qubits on which to apply the inverse QFT. + + Returns: + Circuit: Circuit implementing the inverse QFT. + """ + qft_circ = Circuit() + num_qubits = len(qubits) + + # SWAP gates to reverse qubit order + for i in range(math.floor(num_qubits / 2)): + qft_circ.swap(qubits[i], qubits[-i - 1]) + + # Controlled phase rotations + Hadamard + for k in reversed(range(num_qubits)): + for j in reversed(range(1, num_qubits - k)): + angle = -2 * math.pi / (2 ** (j + 1)) + qft_circ.cphaseshift(qubits[k + j], qubits[k], angle) + qft_circ.h(qubits[k]) + + return qft_circ + + +@circuit.subroutine(register=True) +def controlled_grover( + control: int, target_qubits: QubitSetInput, grover_unitary: np.ndarray +) -> Circuit: + """Apply a controlled Grover operator. + + Applies the controlled-U gate where U is the Grover operator, with the + given control qubit and target qubits. + + Args: + control (int): Index of the control qubit. + target_qubits (QubitSetInput): Indices of target (search) qubits. + grover_unitary (np.ndarray): The Grover operator matrix. + + Returns: + Circuit: Circuit implementing the controlled Grover operator. + """ + circ = Circuit() + + # Build controlled unitary: |0><0| ⊗ I + |1><1| ⊗ U + p0 = np.array([[1.0, 0.0], [0.0, 0.0]]) + p1 = np.array([[0.0, 0.0], [0.0, 1.0]]) + id_matrix = np.eye(len(grover_unitary)) + controlled_matrix = np.kron(p0, id_matrix) + np.kron(p1, grover_unitary) + + targets = [control] + list(target_qubits) + circ.unitary(matrix=controlled_matrix, targets=targets) + + return circ + + +def quantum_counting_circuit( + counting_circ: Circuit, + counting_qubits: QubitSetInput, + search_qubits: QubitSetInput, + grover_matrix: np.ndarray, +) -> Circuit: + """Create the full quantum counting circuit with result types. + + Builds the quantum counting circuit comprising: + 1. Hadamard gates on all counting and search qubits + 2. Controlled-G^(2^k) for each counting qubit k + 3. Inverse QFT on the counting qubits + 4. Probability result type on all qubits + + Args: + counting_circ (Circuit): Initial circuit (may contain setup operations). + counting_qubits (QubitSetInput): Qubits for the counting (precision) register. + search_qubits (QubitSetInput): Qubits for the search register. + grover_matrix (np.ndarray): The Grover operator matrix G. + + Returns: + Circuit: The complete quantum counting circuit with result types. + """ + return counting_circ.quantum_counting( + counting_qubits, search_qubits, grover_matrix + ).probability() + + +@circuit.subroutine(register=True) +def quantum_counting( + counting_qubits: QubitSetInput, + search_qubits: QubitSetInput, + grover_matrix: np.ndarray, +) -> Circuit: + """Build the core quantum counting circuit using QPE on the Grover operator. + + The circuit structure: + 1. Apply H to all counting qubits + 2. Apply H to all search qubits (prepare uniform superposition |s>) + 3. Apply controlled-G^(2^k) for each counting qubit k + 4. Apply inverse QFT to counting qubits + + Args: + counting_qubits (QubitSetInput): Qubits for the counting (precision) register. + search_qubits (QubitSetInput): Qubits for the search register. + grover_matrix (np.ndarray): The Grover operator matrix G. + + Returns: + Circuit: Circuit implementing the quantum counting algorithm. + """ + qc_circ = Circuit() + + # Hadamard on counting qubits + qc_circ.h(counting_qubits) + + # Hadamard on search qubits (prepare |s>) + qc_circ.h(search_qubits) + + # Controlled-G^(2^k) + n_counting = len(counting_qubits) + for ii, qubit in enumerate(reversed(counting_qubits)): + power = 2**ii + g_power = np.linalg.matrix_power(grover_matrix, power) + qc_circ.controlled_grover(qubit, search_qubits, g_power) + + # Inverse QFT on counting qubits + qc_circ.inverse_qft_for_counting(counting_qubits) + + return qc_circ + + +def run_quantum_counting( + circuit: Circuit, + device: Device, + shots: int = 1000, +) -> QuantumTask: + """Run the quantum counting circuit on the given device. + + Args: + circuit (Circuit): The quantum counting circuit. + device (Device): Braket device backend. + shots (int): Number of measurement shots (default 1000). + + Returns: + QuantumTask: Task from running the quantum counting circuit. + """ + return device.run(circuit, shots=shots) + + +def get_quantum_counting_results( + task: QuantumTask, + counting_qubits: QubitSetInput, + search_qubits: QubitSetInput, + verbose: bool = False, +) -> Dict[str, Any]: + """Post-process quantum counting results to estimate the number of marked items. + + After measuring the counting qubits, the most likely outcome y gives + an estimate of the phase φ = y / 2^t. The number of marked items M is: + M = N · sin²(π · φ) + where N = 2^n_search. + + Args: + task (QuantumTask): The task holding quantum counting results. + counting_qubits (QubitSetInput): Qubits of the counting register. + search_qubits (QubitSetInput): Qubits of the search register. + verbose (bool): If True, print detailed results (default False). + + Returns: + Dict[str, Any]: Aggregate measurement results including: + - measurement_counts: raw measurement counts + - counting_register_results: counts collapsed to the counting register + - phases: estimated phases φ for each measured bitstring + - estimated_counts: estimated M for each measured bitstring + - best_estimate: best estimate of M (from most frequent outcome) + - search_space_size: N = 2^n_search + """ + result = task.result() + measurement_counts = result.measurement_counts + n_counting = len(counting_qubits) + n_search = len(search_qubits) + N = 2**n_search + + # Aggregate results on counting register (trace out search qubits) + counting_register_results: Dict[str, int] = {} + if measurement_counts: + for key in measurement_counts.keys(): + counting_bits = key[:n_counting] + counting_register_results[counting_bits] = ( + counting_register_results.get(counting_bits, 0) + + measurement_counts[key] + ) + + # Convert counting register bitstrings to phase estimates and M estimates + phases, estimated_counts = _get_counting_estimates(counting_register_results, n_counting, N) + + # Best estimate from most frequent outcome + if counting_register_results: + best_key = max(counting_register_results, key=counting_register_results.get) + best_y = int(best_key, 2) + best_phase = best_y / (2**n_counting) + best_M = N * (np.sin(np.pi * best_phase) ** 2) + else: + best_key = None + best_M = None + + aggregate_results = { + "measurement_counts": measurement_counts, + "counting_register_results": counting_register_results, + "phases": phases, + "estimated_counts": estimated_counts, + "best_estimate": best_M, + "search_space_size": N, + } + + if verbose: + print(f"Measurement counts: {measurement_counts}") + print(f"Counting register results: {counting_register_results}") + print(f"Phase estimates: {phases}") + print(f"Estimated item counts: {estimated_counts}") + print(f"Best estimate of M: {best_M}") + print(f"Search space size N: {N}") + + return aggregate_results + + +def _get_counting_estimates( + counting_register_results: Dict[str, int], + n_counting: int, + N: int, +) -> Tuple[List[float], List[float]]: + """Convert counting register bitstrings to phase and count estimates. + + Args: + counting_register_results (Dict[str, int]): Measurement results on the counting register. + n_counting (int): Number of counting qubits. + N (int): Search space size. + + Returns: + Tuple[List[float], List[float]]: (phases, estimated_counts) lists, one entry per unique + measured bitstring with counts > 0. + """ + phases = [] + estimated_counts = [] + + for bitstring in counting_register_results: + y = int(bitstring, 2) + phase = y / (2**n_counting) + M_est = N * (np.sin(np.pi * phase) ** 2) + phases.append(phase) + estimated_counts.append(M_est) + + return phases, estimated_counts diff --git a/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py b/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py new file mode 100644 index 00000000..bf3e0f85 --- /dev/null +++ b/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py @@ -0,0 +1,217 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. + +import numpy as np +from braket.circuits import Circuit +from braket.devices import LocalSimulator + +from braket.experimental.algorithms.quantum_counting import quantum_counting as qc + + +# ============================================================ +# Oracle / matrix construction tests +# ============================================================ + + +def test_oracle_matrix_single_marked(): + """Oracle should flip the diagonal entry of the marked state to -1.""" + oracle = qc.build_oracle_matrix(2, [3]) + expected = np.diag([1, 1, 1, -1]) + np.testing.assert_array_equal(oracle, expected) + + +def test_oracle_matrix_multiple_marked(): + """Oracle with multiple marked states should flip all corresponding entries.""" + oracle = qc.build_oracle_matrix(2, [0, 2]) + expected = np.diag([-1, 1, -1, 1]) + np.testing.assert_array_equal(oracle, expected) + + +def test_oracle_matrix_no_marked(): + """Oracle with no marked states should be identity.""" + oracle = qc.build_oracle_matrix(2, []) + expected = np.eye(4) + np.testing.assert_array_equal(oracle, expected) + + +def test_diffusion_matrix(): + """Diffusion matrix for 1-qubit should be [[0, 1], [1, 0]] (X gate).""" + diffusion = qc.build_diffusion_matrix(1) + expected = np.array([[0, 1], [1, 0]]) + np.testing.assert_array_almost_equal(diffusion, expected) + + +def test_grover_matrix_unitarity(): + """Grover matrix should be unitary.""" + grover = qc.build_grover_matrix(2, [1]) + product = grover @ grover.T + np.testing.assert_array_almost_equal(product, np.eye(4), decimal=10) + + +# ============================================================ +# Circuit construction tests +# ============================================================ + + +def test_quantum_counting_circuit_construction(): + """Circuit should have expected gate structure.""" + counting_qubits = [0, 1] + search_qubits = [2] + marked_states = [0] + grover = qc.build_grover_matrix(1, marked_states) + + circ = Circuit() + circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, grover) + + # The circuit should have instructions (Hadamard + controlled unitaries + QFT) + assert len(circ.instructions) > 0 + # Should have result types (probability) + assert len(circ.result_types) > 0 + + +def test_inverse_qft_for_counting_2_qubits(): + """Inverse QFT on 2 qubits should produce correct gate count.""" + qubits = [0, 1] + qft_circ = qc.inverse_qft_for_counting(qubits) + + # 2-qubit inverse QFT: 1 SWAP + 1 CPHASE + 2 H = 4 instructions + assert len(qft_circ.instructions) == 4 + + +# ============================================================ +# End-to-end counting tests +# ============================================================ + + +def test_count_1_of_4(): + """Quantum counting should estimate M ≈ 1 for 1 marked item out of 4.""" + counting_qubits = [0, 1, 2, 3] + search_qubits = [4, 5] + marked_states = [3] + grover = qc.build_grover_matrix(2, marked_states) + + circ = Circuit() + circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, grover) + + device = LocalSimulator() + task = qc.run_quantum_counting(circ, device, shots=1000) + + results = qc.get_quantum_counting_results( + task, counting_qubits, search_qubits, verbose=True + ) + + # Best estimate should be close to 1 + assert results["best_estimate"] is not None + assert results["search_space_size"] == 4 + assert abs(results["best_estimate"] - 1.0) < 1.5 + + +def test_count_0_of_4(): + """Quantum counting should estimate M ≈ 0 when no items are marked.""" + counting_qubits = [0, 1, 2, 3] + search_qubits = [4, 5] + marked_states = [] + grover = qc.build_grover_matrix(2, marked_states) + + circ = Circuit() + circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, grover) + + device = LocalSimulator() + task = qc.run_quantum_counting(circ, device, shots=1000) + + results = qc.get_quantum_counting_results( + task, counting_qubits, search_qubits, verbose=True + ) + + # With no marked items, the most common measurement should yield M ≈ 0 + assert results["best_estimate"] is not None + assert abs(results["best_estimate"] - 0.0) < 0.5 + + +def test_count_4_of_4(): + """Quantum counting should estimate M ≈ 4 when all items are marked.""" + counting_qubits = [0, 1, 2, 3] + search_qubits = [4, 5] + marked_states = [0, 1, 2, 3] + grover = qc.build_grover_matrix(2, marked_states) + + circ = Circuit() + circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, grover) + + device = LocalSimulator() + task = qc.run_quantum_counting(circ, device, shots=1000) + + results = qc.get_quantum_counting_results( + task, counting_qubits, search_qubits, verbose=True + ) + + # With all items marked, M should be ≈ 4 + assert results["best_estimate"] is not None + assert abs(results["best_estimate"] - 4.0) < 0.5 + + +def test_count_2_of_8(): + """Quantum counting should estimate M ≈ 2 for 2 marked items out of 8.""" + counting_qubits = [0, 1, 2, 3, 4] + search_qubits = [5, 6, 7] + marked_states = [2, 5] + grover = qc.build_grover_matrix(3, marked_states) + + circ = Circuit() + circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, grover) + + device = LocalSimulator() + task = qc.run_quantum_counting(circ, device, shots=2000) + + results = qc.get_quantum_counting_results( + task, counting_qubits, search_qubits, verbose=True + ) + + # Best estimate should be close to 2 + assert results["best_estimate"] is not None + assert results["search_space_size"] == 8 + assert abs(results["best_estimate"] - 2.0) < 1.5 + + +def test_oracle_invalid_state_raises(): + """Building oracle with out-of-range state should raise ValueError.""" + try: + qc.build_oracle_matrix(2, [4]) # 4 is out of range for 2 qubits (max=3) + assert False, "Should have raised ValueError" + except ValueError: + pass + + +def test_counting_results_have_correct_keys(): + """Results dict should contain all expected keys.""" + counting_qubits = [0, 1, 2] + search_qubits = [3] + grover = qc.build_grover_matrix(1, [0]) + + circ = Circuit() + circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, grover) + + device = LocalSimulator() + task = qc.run_quantum_counting(circ, device, shots=100) + + results = qc.get_quantum_counting_results(task, counting_qubits, search_qubits) + + expected_keys = { + "measurement_counts", + "counting_register_results", + "phases", + "estimated_counts", + "best_estimate", + "search_space_size", + } + assert set(results.keys()) == expected_keys From 423bd44d635c088cdc0c0d2a27e14c2deea93948 Mon Sep 17 00:00:00 2001 From: axif Date: Mon, 16 Feb 2026 01:39:14 +0600 Subject: [PATCH 2/8] Add cell IDs, clear execution counts, and update notebook format --- .../textbook/Quantum_Counting_Algorithm.ipynb | 92 ++++++++++++------- 1 file changed, 57 insertions(+), 35 deletions(-) diff --git a/notebooks/textbook/Quantum_Counting_Algorithm.ipynb b/notebooks/textbook/Quantum_Counting_Algorithm.ipynb index ddf6aa20..bb7ec237 100644 --- a/notebooks/textbook/Quantum_Counting_Algorithm.ipynb +++ b/notebooks/textbook/Quantum_Counting_Algorithm.ipynb @@ -9,7 +9,8 @@ "The Quantum Counting algorithm, introduced by Brassard, Høyer, and Tapp [1], counts the number of marked items $M$ in an unstructured database of $N = 2^n$ elements. It combines **Grover's search operator** with **Quantum Phase Estimation (QPE)** to achieve a quadratic speedup over classical counting, requiring only $O(\\sqrt{N})$ oracle queries instead of the classical $\\Theta(N)$.\n", "\n", "**Key idea:** The Grover operator $G = D \\cdot O$ has eigenvalues $e^{\\pm i\\theta}$, where $\\theta$ satisfies $\\sin^2(\\theta/2) = M/N$. By applying QPE to $G$, we estimate $\\theta$ and hence determine $M$." - ] + ], + "id": "b7179342-351f-4f11-b9ac-344ab728a9b0" }, { "cell_type": "markdown", @@ -20,11 +21,12 @@ "[[1] G. Brassard, P. Høyer, and A. Tapp, \"Quantum Counting\", Proceedings of ICALP 1998](https://arxiv.org/abs/quant-ph/9805082)\n", "\n", "[[2] M. Nielsen and I. Chuang, Quantum Computation and Quantum Information, Cambridge University Press, 2010](https://www.cambridge.org/highereducation/books/quantum-computation-and-quantum-information/01E10196D0A682A6AEFFEA52D53BE9AE)" - ] + ], + "id": "01fb7ecc-66ee-420b-95fc-196d58d23f07" }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -42,7 +44,8 @@ ")\n", "\n", "%matplotlib inline" - ] + ], + "id": "b9bdcb62-8bce-4811-8ae2-9597f1340634" }, { "cell_type": "markdown", @@ -65,18 +68,20 @@ "The eigenvalues of $G$ are $e^{\\pm i\\theta}$. QPE with $t$ precision (counting) qubits estimates the phase $\\varphi = \\theta/(2\\pi)$ as a $t$-bit fraction $y/2^t$. From $\\varphi$, we recover:\n", "\n", "$$M = N \\cdot \\sin^2(\\pi \\varphi)$$" - ] + ], + "id": "a0df5ef1-1622-403c-8e44-d310d754d177" }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Prepare the Oracle and Grover Operator" - ] + ], + "id": "1ff75da5-558a-495f-93ff-e586239b9f14" }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -118,18 +123,20 @@ "# Verify eigenvalues\n", "eigenvalues = np.linalg.eigvals(grover)\n", "print(f\"\\nEigenvalues of G: {np.round(eigenvalues, 4)}\")" - ] + ], + "id": "49c4b0e1-8bbc-441c-adec-3be22125a358" }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Build and Print the Quantum Counting Circuit" - ] + ], + "id": "fee13411-62cb-41a0-91b6-32f2060b65f6" }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -182,18 +189,20 @@ "\n", "print(\"\\nQuantum Counting Circuit:\")\n", "print(circ)" - ] + ], + "id": "d4537c2f-52dc-4126-9a91-26fdf5d0633b" }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Run on a Local Simulator" - ] + ], + "id": "3bc6f5fe-3771-47ce-a6eb-5d8b2d93442a" }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -235,11 +244,12 @@ "print(f\"Actual M = {len(marked_states)}\")\n", "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")\n", "print(f\"Absolute error: {abs(len(marked_states) - results['best_estimate']):.4f}\")" - ] + ], + "id": "8a31859a-8bc7-4901-a787-2dafc3c12fc8" }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -269,7 +279,8 @@ "plt.xticks(rotation=45)\n", "plt.tight_layout()\n", "plt.show()" - ] + ], + "id": "2ef4d059-766f-4045-b637-2b6a87ce64ae" }, { "cell_type": "markdown", @@ -278,11 +289,12 @@ "## Example 2: Counting Multiple Marked Items\n", "\n", "Count 2 marked items in an 8-element search space ($N = 8$, $n = 3$)." - ] + ], + "id": "fa08c609-3033-41de-9cf4-3cc669412740" }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -325,7 +337,8 @@ "\n", "print(f\"\\nActual M = {len(marked_states)}\")\n", "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")" - ] + ], + "id": "e8901c56-66f3-4428-89a9-ceee58082bb1" }, { "cell_type": "markdown", @@ -334,11 +347,12 @@ "## Example 3: Edge Case — No Marked Items (M = 0)\n", "\n", "When no items are marked, the algorithm should estimate $M \\approx 0$." - ] + ], + "id": "ba1c59de-2601-4c7b-a9bf-481e5ea5fabf" }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -379,7 +393,8 @@ "\n", "print(f\"\\nActual M = 0\")\n", "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")" - ] + ], + "id": "e1f273c0-bc56-4d13-9f97-ef9f879d3d27" }, { "cell_type": "markdown", @@ -388,11 +403,12 @@ "## Example 4: Edge Case — All Items Marked (M = N)\n", "\n", "When all items are marked, $M = N$." - ] + ], + "id": "c224af69-fd26-4997-bcc7-86bb1c35d4f4" }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -433,7 +449,8 @@ "\n", "print(f\"\\nActual M = {N}\")\n", "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")" - ] + ], + "id": "36cbb24d-a2d5-44b3-8496-42d5c6335473" }, { "cell_type": "markdown", @@ -442,11 +459,12 @@ "## [Optional] Run on a QPU or Managed Simulator\n", "\n", "[Include estimated price for running in USD using the [cost tracker](https://docs.aws.amazon.com/braket/latest/developerguide/braket-pricing.html#real-time-cost-tracking).]" - ] + ], + "id": "5d747213-799b-4be7-a5b9-efc3c9bd57a6" }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -454,11 +472,12 @@ "# from braket.tracking import Tracker\n", "\n", "# tracker = Tracker().start()" - ] + ], + "id": "690a8210-747e-4c22-882f-60b516a2f201" }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -489,11 +508,12 @@ "# task, counting_qubits, search_qubits, verbose=True\n", "# )\n", "# print(f\"\\nEstimated M ≈ {results['best_estimate']:.4f}\")" - ] + ], + "id": "2c70f923-0cce-49ab-a382-1a4c7fd296a8" }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -502,14 +522,16 @@ "# print(\n", "# f\"Estimated cost to run this example: {tracker.qpu_tasks_cost() + tracker.simulator_tasks_cost():.2f} USD\"\n", "# )" - ] + ], + "id": "1c2e7121-a3d3-42c7-b334-3ba29785617b" }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note: Charges shown are estimates based on your Amazon Braket simulator and quantum processing unit (QPU) task usage. Estimated charges shown may differ from your actual charges. Estimated charges do not factor in any discounts or credits, and you may experience additional charges based on your use of other services such as Amazon Elastic Compute Cloud (Amazon EC2)." - ] + ], + "id": "2ab582fd-c942-4207-a218-9d13fc73317b" } ], "metadata": { @@ -532,5 +554,5 @@ } }, "nbformat": 4, - "nbformat_minor": 2 -} + "nbformat_minor": 5 +} \ No newline at end of file From c6fa3a965fe1e910b8b004f398b71852d426189a Mon Sep 17 00:00:00 2001 From: axif Date: Wed, 18 Feb 2026 16:35:10 +0600 Subject: [PATCH 3/8] Refactor notebook formatting and improve code readability --- .../1_Shot_Allocation.ipynb | 243 ++++++++++++------ .../2_Adaptive_Shot_Allocation.ipynb | 208 ++++++++++----- .../adaptive_allocation_notebook_helpers.py | 7 +- notebooks/textbook/CHSH_Inequality.ipynb | 2 +- .../textbook/Quantum_Counting_Algorithm.ipynb | 114 ++++---- .../adaptive_allocator.py | 179 +++++++------ .../adaptive_allocator_braket_helpers.py | 52 ++-- .../quantum_counting/quantum_counting.py | 5 +- .../test_adaptive_allocator.py | 98 +++---- .../quantum_counting/test_quantum_counting.py | 16 +- 10 files changed, 548 insertions(+), 376 deletions(-) diff --git a/notebooks/advanced_algorithms/adaptive_shot_allocation/1_Shot_Allocation.ipynb b/notebooks/advanced_algorithms/adaptive_shot_allocation/1_Shot_Allocation.ipynb index c8a78f33..8de2d2e2 100644 --- a/notebooks/advanced_algorithms/adaptive_shot_allocation/1_Shot_Allocation.ipynb +++ b/notebooks/advanced_algorithms/adaptive_shot_allocation/1_Shot_Allocation.ipynb @@ -104,11 +104,14 @@ ], "source": [ "# Create a parameterized circuit with random angles\n", - "random_state = (Circuit()\n", - " .ry(angle = np.random.rand()*np.pi, target=0).ry(angle = np.random.rand()*np.pi, target=1)\n", - " .cnot(control=0, target=1)\n", - " .ry(angle = np.random.rand()*np.pi, target=0).ry(angle = np.random.rand()*np.pi, target=1)\n", - " )\n", + "random_state = (\n", + " Circuit()\n", + " .ry(angle=np.random.rand() * np.pi, target=0)\n", + " .ry(angle=np.random.rand() * np.pi, target=1)\n", + " .cnot(control=0, target=1)\n", + " .ry(angle=np.random.rand() * np.pi, target=0)\n", + " .ry(angle=np.random.rand() * np.pi, target=1)\n", + ")\n", "\n", "print(random_state)" ] @@ -159,29 +162,30 @@ "# Set up local simulator device\n", "device = LocalSimulator()\n", "\n", + "\n", "def compute_expectation_value_approximation(state, shot_configuration):\n", " \"\"\"Compute approximate expectation value using specified shot allocation.\n", - " \n", + "\n", " Args:\n", " state (Circuit): Quantum circuit representing the state\n", " shot_configuration (list): Number of shots for each Pauli term\n", - " \n", + "\n", " Returns:\n", " float: Approximated expectation value\n", " \"\"\"\n", - " assert (len(shot_configuration)==len(paulis))\n", + " assert len(shot_configuration) == len(paulis)\n", " expectation_value = 0.0\n", - " \n", + "\n", " for i, term in enumerate(paulis):\n", " # Define a circuit measuring the specific term on the given state\n", " circuit = state.copy().sample(term)\n", - " \n", + "\n", " # Execute measurements and get results (±1)\n", - " measurements = device.run(circuit, shots = shot_configuration[i]).result().values[0]\n", - " \n", + " measurements = device.run(circuit, shots=shot_configuration[i]).result().values[0]\n", + "\n", " # Calculate term's contribution: mean of measurements × coefficient\n", - " expectation_value += coeffs[i]*np.mean(measurements, dtype=float)\n", - " \n", + " expectation_value += coeffs[i] * np.mean(measurements, dtype=float)\n", + "\n", " return expectation_value" ] }, @@ -201,25 +205,26 @@ "source": [ "def get_exact_expectation_value(state):\n", " \"\"\"Compute exact expectation value using state vector simulation.\n", - " \n", + "\n", " Args:\n", " state (Circuit): Quantum circuit representing the state\n", - " \n", + "\n", " Returns:\n", " float: Exact expectation value\n", " \"\"\"\n", " expectation_value = 0.0\n", - " \n", + "\n", " for i, term in enumerate(paulis):\n", " # Calculate exact expectation for each term\n", " circuit = state.copy().expectation(term)\n", - " normalized_expectation = device.run(circuit, shots = 0).result().values[0]\n", - " \n", + " normalized_expectation = device.run(circuit, shots=0).result().values[0]\n", + "\n", " # Add term's contribution: exact expectation × coefficient\n", - " expectation_value += coeffs[i]*normalized_expectation\n", - " \n", + " expectation_value += coeffs[i] * normalized_expectation\n", + "\n", " return expectation_value\n", "\n", + "\n", "# Calculate exact expectation value for reference\n", "exact_expectation = get_exact_expectation_value(random_state)\n", "print(f\"Exact expectation value: {exact_expectation:.6f}\")" @@ -252,12 +257,16 @@ "uniform_shot_allocation = [400, 400, 400]\n", "\n", "# Run multiple trials to get statistics\n", - "uniform_values = [compute_expectation_value_approximation(random_state, uniform_shot_allocation) for _ in range(1000)]\n", + "uniform_values = [\n", + " compute_expectation_value_approximation(random_state, uniform_shot_allocation)\n", + " for _ in range(1000)\n", + "]\n", "uniform_mean = np.mean(uniform_values)\n", "uniform_std = np.std(uniform_values)\n", "\n", - "print(f\"Uniform allocation ({uniform_shot_allocation}):\\n\"\n", - " f\"Mean: {uniform_mean:.6f} ± {uniform_std:.6f}\")" + "print(\n", + " f\"Uniform allocation ({uniform_shot_allocation}):\\nMean: {uniform_mean:.6f} ± {uniform_std:.6f}\"\n", + ")" ] }, { @@ -284,30 +293,47 @@ } ], "source": [ - "def plot_histograms(data, labels, colors, exact_expectation, title, y_max = 150):\n", + "def plot_histograms(data, labels, colors, exact_expectation, title, y_max=150):\n", " num_sets = len(data)\n", - " assert (len(labels) == num_sets)\n", - " assert (len(colors) == num_sets)\n", - " \n", + " assert len(labels) == num_sets\n", + " assert len(colors) == num_sets\n", + "\n", " plt.figure(figsize=(10, 6))\n", " for i in range(num_sets):\n", - " plt.hist(data[i], alpha=0.5, bins=np.arange(exact_expectation-1, exact_expectation+1, 0.025),\n", - " color=colors[i], label=labels[i])\n", - " \n", + " plt.hist(\n", + " data[i],\n", + " alpha=0.5,\n", + " bins=np.arange(exact_expectation - 1, exact_expectation + 1, 0.025),\n", + " color=colors[i],\n", + " label=labels[i],\n", + " )\n", + "\n", " if not y_max:\n", " y_max = int(np.ceil(plt.ylim()[1]))\n", - " \n", - " plt.ylim(0,y_max)\n", - " ev_line_height = (2*y_max//3)\n", - " plt.plot([exact_expectation]*ev_line_height, np.arange(ev_line_height), color=\"black\", label=\"Exact value\")\n", - " \n", + "\n", + " plt.ylim(0, y_max)\n", + " ev_line_height = 2 * y_max // 3\n", + " plt.plot(\n", + " [exact_expectation] * ev_line_height,\n", + " np.arange(ev_line_height),\n", + " color=\"black\",\n", + " label=\"Exact value\",\n", + " )\n", + "\n", " plt.xlabel(\"Expectation Value\")\n", " plt.ylabel(\"Frequency\")\n", " plt.legend()\n", " plt.title(title)\n", " plt.grid(True, alpha=0.3)\n", "\n", - "plot_histograms([uniform_values], [\"Uniform shot allocation\"], [\"red\"], exact_expectation, \"Distribution of Results with Uniform Shot Allocation\")" + "\n", + "plot_histograms(\n", + " [uniform_values],\n", + " [\"Uniform shot allocation\"],\n", + " [\"red\"],\n", + " exact_expectation,\n", + " \"Distribution of Results with Uniform Shot Allocation\",\n", + ")" ] }, { @@ -342,12 +368,17 @@ "weighted_shot_allocation = [100, 100, 1000]\n", "\n", "# Run multiple trials to get statistics\n", - "weighted_values = [compute_expectation_value_approximation(random_state, weighted_shot_allocation) for _ in range(1000)]\n", + "weighted_values = [\n", + " compute_expectation_value_approximation(random_state, weighted_shot_allocation)\n", + " for _ in range(1000)\n", + "]\n", "weighted_mean = np.mean(weighted_values)\n", "weighted_std = np.std(weighted_values)\n", "\n", - "print(f\"Coefficient-weighted allocation ({weighted_shot_allocation}):\\n\"\n", - " f\"Mean: {weighted_mean:.6f} ± {weighted_std:.6f}\")" + "print(\n", + " f\"Coefficient-weighted allocation ({weighted_shot_allocation}):\\n\"\n", + " f\"Mean: {weighted_mean:.6f} ± {weighted_std:.6f}\"\n", + ")" ] }, { @@ -367,8 +398,13 @@ } ], "source": [ - "plot_histograms([uniform_values, weighted_values], [\"Uniform allocation\", \"Coefficient-weighted allocation\"], [\"red\", \"blue\"], \n", - " exact_expectation, \"Comparison of Shot Allocation Strategies\")" + "plot_histograms(\n", + " [uniform_values, weighted_values],\n", + " [\"Uniform allocation\", \"Coefficient-weighted allocation\"],\n", + " [\"red\", \"blue\"],\n", + " exact_expectation,\n", + " \"Comparison of Shot Allocation Strategies\",\n", + ")" ] }, { @@ -425,7 +461,9 @@ ], "source": [ "# Prepare uniform superposition state\n", - "uniform_superposition_state = Circuit().h(0).h(1) # Apply Hadamard gates to create uniform superposition\n", + "uniform_superposition_state = (\n", + " Circuit().h(0).h(1)\n", + ") # Apply Hadamard gates to create uniform superposition\n", "print(uniform_superposition_state)\n", "\n", "exact_expectation = get_exact_expectation_value(uniform_superposition_state)\n", @@ -458,14 +496,24 @@ ], "source": [ "# Compare uniform and weighted allocations\n", - "uniform_values = [compute_expectation_value_approximation(uniform_superposition_state, uniform_shot_allocation) for _ in range(1000)]\n", - "weighted_values = [compute_expectation_value_approximation(uniform_superposition_state, weighted_shot_allocation) for _ in range(1000)]\n", - "\n", - "print(f\"Uniform allocation ({uniform_shot_allocation}):\\n\"\n", - " f\"Mean: {np.mean(uniform_values):.6f} ± {np.std(uniform_values):.6f}\\n\")\n", + "uniform_values = [\n", + " compute_expectation_value_approximation(uniform_superposition_state, uniform_shot_allocation)\n", + " for _ in range(1000)\n", + "]\n", + "weighted_values = [\n", + " compute_expectation_value_approximation(uniform_superposition_state, weighted_shot_allocation)\n", + " for _ in range(1000)\n", + "]\n", + "\n", + "print(\n", + " f\"Uniform allocation ({uniform_shot_allocation}):\\n\"\n", + " f\"Mean: {np.mean(uniform_values):.6f} ± {np.std(uniform_values):.6f}\\n\"\n", + ")\n", "\n", - "print(f\"Coefficient-weighted allocation ({weighted_shot_allocation}):\\n\"\n", - " f\"Mean: {np.mean(weighted_values):.6f} ± {np.std(weighted_values):.6f}\")" + "print(\n", + " f\"Coefficient-weighted allocation ({weighted_shot_allocation}):\\n\"\n", + " f\"Mean: {np.mean(weighted_values):.6f} ± {np.std(weighted_values):.6f}\"\n", + ")" ] }, { @@ -485,8 +533,14 @@ } ], "source": [ - "plot_histograms([uniform_values, weighted_values], [\"Uniform allocation\", \"Coefficient-weighted allocation\"], [\"red\", \"blue\"], \n", - " exact_expectation, \"Comparison for Uniform Superposition State\", y_max = 250)" + "plot_histograms(\n", + " [uniform_values, weighted_values],\n", + " [\"Uniform allocation\", \"Coefficient-weighted allocation\"],\n", + " [\"red\", \"blue\"],\n", + " exact_expectation,\n", + " \"Comparison for Uniform Superposition State\",\n", + " y_max=250,\n", + ")" ] }, { @@ -541,12 +595,16 @@ "source": [ "optimal_shot_allocation = [600, 599, 1]\n", "\n", - "optimal_values = [compute_expectation_value_approximation(uniform_superposition_state, optimal_shot_allocation) for _ in range(1000)]\n", + "optimal_values = [\n", + " compute_expectation_value_approximation(uniform_superposition_state, optimal_shot_allocation)\n", + " for _ in range(1000)\n", + "]\n", "optimal_mean = np.mean(optimal_values)\n", "optimal_std = np.std(optimal_values)\n", "\n", - "print(f\"Optimal allocation ({optimal_shot_allocation}):\\n\"\n", - " f\"Mean: {optimal_mean:.6f} ± {optimal_std:.6f}\")" + "print(\n", + " f\"Optimal allocation ({optimal_shot_allocation}):\\nMean: {optimal_mean:.6f} ± {optimal_std:.6f}\"\n", + ")" ] }, { @@ -566,8 +624,14 @@ } ], "source": [ - "plot_histograms([uniform_values, optimal_values], [\"Uniform allocation\", \"Optimal allocation\"], [\"red\", \"cyan\"], \n", - " exact_expectation, \"Comparison with Optimal Shot Allocation\", y_max = 250)" + "plot_histograms(\n", + " [uniform_values, optimal_values],\n", + " [\"Uniform allocation\", \"Optimal allocation\"],\n", + " [\"red\", \"cyan\"],\n", + " exact_expectation,\n", + " \"Comparison with Optimal Shot Allocation\",\n", + " y_max=250,\n", + ")" ] }, { @@ -586,36 +650,40 @@ "metadata": {}, "outputs": [], "source": [ - "def compute_grouped_expectation_value_approximation(state, observable_index_groups, shot_configuration):\n", + "def compute_grouped_expectation_value_approximation(\n", + " state, observable_index_groups, shot_configuration\n", + "):\n", " \"\"\"Compute expectation value using grouped measurements where possible.\n", - " \n", + "\n", " Args:\n", " state (Circuit): Quantum circuit representing the state\n", " observable_index_groups (list): Groups of observable indices that can be measured together\n", " shot_configuration (list): Number of shots for each group\n", - " \n", + "\n", " Returns:\n", " float: Approximated expectation value\n", " \"\"\"\n", - " assert (len(shot_configuration)==len(observable_index_groups))\n", + " assert len(shot_configuration) == len(observable_index_groups)\n", " expectation_value = 0.0\n", - " \n", + "\n", " for i, group in enumerate(observable_index_groups):\n", " if isinstance(group, int): # Allow single indices to be passed directly\n", " group = [group]\n", - " \n", + "\n", " # Set up circuit to measure all observables in this group\n", " circuit = state.copy()\n", " for term in group:\n", " circuit.sample(paulis[term])\n", - " \n", + "\n", " # Get measurements for all observables in the group\n", - " measurements = device.run(circuit, shots = shot_configuration[i]).result().values\n", - " \n", + " measurements = device.run(circuit, shots=shot_configuration[i]).result().values\n", + "\n", " # Process each observable's measurements\n", " for idx_in_group, idx_global in enumerate(group):\n", - " expectation_value += coeffs[idx_global]*np.mean(measurements[idx_in_group], dtype=float)\n", - " \n", + " expectation_value += coeffs[idx_global] * np.mean(\n", + " measurements[idx_in_group], dtype=float\n", + " )\n", + "\n", " return expectation_value" ] }, @@ -635,14 +703,20 @@ ], "source": [ "# Group ZI and IZ together, measure XX separately\n", - "grouped_optimal_values = [compute_grouped_expectation_value_approximation(uniform_superposition_state, [[0,1], 2], [1199, 1]) \n", - " for _ in range(1000)]\n", + "grouped_optimal_values = [\n", + " compute_grouped_expectation_value_approximation(\n", + " uniform_superposition_state, [[0, 1], 2], [1199, 1]\n", + " )\n", + " for _ in range(1000)\n", + "]\n", "\n", "grouped_mean = np.mean(grouped_optimal_values)\n", "grouped_std = np.std(grouped_optimal_values)\n", "\n", - "print(f\"Grouped optimal allocation ([1199, 1] shots for [[ZI,IZ], XX]):\\n\"\n", - " f\"Mean: {grouped_mean:.6f} ± {grouped_std:.6f}\")" + "print(\n", + " f\"Grouped optimal allocation ([1199, 1] shots for [[ZI,IZ], XX]):\\n\"\n", + " f\"Mean: {grouped_mean:.6f} ± {grouped_std:.6f}\"\n", + ")" ] }, { @@ -662,8 +736,14 @@ } ], "source": [ - "plot_histograms([optimal_values, grouped_optimal_values], [\"Optimal allocation (separate terms)\", \"Optimal allocation (grouped terms)\"],\n", - " [\"cyan\", \"green\"], exact_expectation, \"Comparison of Optimal Strategies\", y_max = 250)" + "plot_histograms(\n", + " [optimal_values, grouped_optimal_values],\n", + " [\"Optimal allocation (separate terms)\", \"Optimal allocation (grouped terms)\"],\n", + " [\"cyan\", \"green\"],\n", + " exact_expectation,\n", + " \"Comparison of Optimal Strategies\",\n", + " y_max=250,\n", + ")" ] }, { @@ -732,14 +812,15 @@ " run_adaptive_allocation,\n", ")\n", "\n", - "estimator = AdaptiveShotAllocator(['IZ', 'ZI', 'XX'], [1.0, 1.0, 10.0])\n", + "estimator = AdaptiveShotAllocator([\"IZ\", \"ZI\", \"XX\"], [1.0, 1.0, 10.0])\n", "\n", "adaptive_values = []\n", "\n", "for _ in tqdm(range(1000)):\n", " estimator.reset()\n", "\n", - " adaptive_values.append(estimator.expectation_from_measurements(\n", + " adaptive_values.append(\n", + " estimator.expectation_from_measurements(\n", " run_adaptive_allocation(device, uniform_superposition_state, estimator, 100, 12)\n", " )\n", " )" @@ -771,8 +852,14 @@ } ], "source": [ - "plot_histograms([grouped_optimal_values, adaptive_values], [\"Optimal allocation\", \"Adaptive allocation\"], [\"green\", \"cyan\"], \n", - " exact_expectation, \"Comparison of Optimal and Adaptive Shot Allocation Strategies\", y_max = 250)" + "plot_histograms(\n", + " [grouped_optimal_values, adaptive_values],\n", + " [\"Optimal allocation\", \"Adaptive allocation\"],\n", + " [\"green\", \"cyan\"],\n", + " exact_expectation,\n", + " \"Comparison of Optimal and Adaptive Shot Allocation Strategies\",\n", + " y_max=250,\n", + ")" ] }, { diff --git a/notebooks/advanced_algorithms/adaptive_shot_allocation/2_Adaptive_Shot_Allocation.ipynb b/notebooks/advanced_algorithms/adaptive_shot_allocation/2_Adaptive_Shot_Allocation.ipynb index 4938fcb3..86c37259 100644 --- a/notebooks/advanced_algorithms/adaptive_shot_allocation/2_Adaptive_Shot_Allocation.ipynb +++ b/notebooks/advanced_algorithms/adaptive_shot_allocation/2_Adaptive_Shot_Allocation.ipynb @@ -123,9 +123,15 @@ "\n", "estimator = AdaptiveShotAllocator(paulis, coeffs)\n", "\n", - "print(\"Identified commuting groups:\", [ [paulis[p] for p in commuting_group] for commuting_group in estimator.cliq])\n", + "print(\n", + " \"Identified commuting groups:\",\n", + " [[paulis[p] for p in commuting_group] for commuting_group in estimator.cliq],\n", + ")\n", "\n", - "print(\"Proposed allocation (shots per group) w/o prior measurement knowledge: \", estimator.incremental_shot_allocation(1200))" + "print(\n", + " \"Proposed allocation (shots per group) w/o prior measurement knowledge: \",\n", + " estimator.incremental_shot_allocation(1200),\n", + ")" ] }, { @@ -178,20 +184,21 @@ " # To that end, we keep track of the measurements in a 2-D array, recording the number of different outcomes.\n", " # DETAILS: `measurements[i][j][(-1,1)]`, for example, records the number of times observables `i` and `j`\n", " # were measured together and recorded values of `-1` adn `1` respectively.\n", - " measurements = [[{(1, 1): 0, (1, -1): 0, (-1, 1): 0, (-1, -1): 0}\n", - " for _ in range(hamiltonian_terms)]\n", - " for _ in range(hamiltonian_terms)]\n", + " measurements = [\n", + " [{(1, 1): 0, (1, -1): 0, (-1, 1): 0, (-1, -1): 0} for _ in range(hamiltonian_terms)]\n", + " for _ in range(hamiltonian_terms)\n", + " ]\n", "\n", " # STEP 2: Perform the measurements ()\n", " for shot_id in range(shots[0]):\n", " state = np.random.randint(4)\n", - " measurement_IZ = 1 - 2*(state%2)\n", - " measurement_ZI = 1 - 2*(state//2)\n", + " measurement_IZ = 1 - 2 * (state % 2)\n", + " measurement_ZI = 1 - 2 * (state // 2)\n", " measurements[0][0][(measurement_IZ, measurement_IZ)] += 1\n", " measurements[1][1][(measurement_ZI, measurement_ZI)] += 1\n", " measurements[0][1][(measurement_IZ, measurement_ZI)] += 1\n", - " measurements[1][0][(measurement_ZI, measurement_IZ)] += 1 \n", - " \n", + " measurements[1][0][(measurement_ZI, measurement_IZ)] += 1\n", + "\n", " for shot_id in range(shots[1]):\n", " measurement_XX = 1\n", " measurements[2][2][(measurement_XX, measurement_XX)] += 1\n", @@ -225,7 +232,9 @@ } ], "source": [ - "print(f\"Estimated expectation value: {estimator.expectation_from_measurements():.6f} ± {estimator.error_estimate():.6f}\")" + "print(\n", + " f\"Estimated expectation value: {estimator.expectation_from_measurements():.6f} ± {estimator.error_estimate():.6f}\"\n", + ")" ] }, { @@ -333,15 +342,64 @@ ], "source": [ "# Note that, as would be the case in practice, we have removed the IIII term and its cofficient from the calculations below\n", - "paulis = ['IIII', 'XXXI', 'XXXZ', 'XYYI', 'XZXI', 'XZXZ', 'YXYI', 'YXYZ', 'YYXI', 'YZYI', 'YZYZ', 'ZIII',\n", - " 'ZXZI', 'ZXZZ', 'ZXIZ', 'ZZII', 'ZZZI', 'ZZZZ', 'ZIZI', 'ZIZZ', 'IXII', 'IXZI', 'IXIZ', 'IZII',\n", - " 'IZZZ', 'IZIZ', 'IIZI'][1:]\n", - "coeffs = [-14.440090444958097, 0.01396784712709576, 0.0050449972385411684, 0.008922759379312662, 0.004572316311895031, \n", - " 0.004572316311895031, 0.01396784712709576, 0.0050449972385411684, -0.008922759379312662, 0.004572316311895031, \n", - " 0.004572316311895031, 0.37322478932293823, 0.01396784712709576, 0.0050449972385411684, -0.008922759379312663, \n", - " 0.37322478932293823, 0.06754531038829523, 0.06754531038829523, 0.0629729940764002, 0.0629729940764002, \n", - " -0.0050449972385411684, 0.008922759379312663, -0.01396784712709576, 0.1377331477309217, 0.18592768458263145, \n", - " 0.10062930161995226, 0.18592768458263148][1:]\n", + "paulis = [\n", + " \"IIII\",\n", + " \"XXXI\",\n", + " \"XXXZ\",\n", + " \"XYYI\",\n", + " \"XZXI\",\n", + " \"XZXZ\",\n", + " \"YXYI\",\n", + " \"YXYZ\",\n", + " \"YYXI\",\n", + " \"YZYI\",\n", + " \"YZYZ\",\n", + " \"ZIII\",\n", + " \"ZXZI\",\n", + " \"ZXZZ\",\n", + " \"ZXIZ\",\n", + " \"ZZII\",\n", + " \"ZZZI\",\n", + " \"ZZZZ\",\n", + " \"ZIZI\",\n", + " \"ZIZZ\",\n", + " \"IXII\",\n", + " \"IXZI\",\n", + " \"IXIZ\",\n", + " \"IZII\",\n", + " \"IZZZ\",\n", + " \"IZIZ\",\n", + " \"IIZI\",\n", + "][1:]\n", + "coeffs = [\n", + " -14.440090444958097,\n", + " 0.01396784712709576,\n", + " 0.0050449972385411684,\n", + " 0.008922759379312662,\n", + " 0.004572316311895031,\n", + " 0.004572316311895031,\n", + " 0.01396784712709576,\n", + " 0.0050449972385411684,\n", + " -0.008922759379312662,\n", + " 0.004572316311895031,\n", + " 0.004572316311895031,\n", + " 0.37322478932293823,\n", + " 0.01396784712709576,\n", + " 0.0050449972385411684,\n", + " -0.008922759379312663,\n", + " 0.37322478932293823,\n", + " 0.06754531038829523,\n", + " 0.06754531038829523,\n", + " 0.0629729940764002,\n", + " 0.0629729940764002,\n", + " -0.0050449972385411684,\n", + " 0.008922759379312663,\n", + " -0.01396784712709576,\n", + " 0.1377331477309217,\n", + " 0.18592768458263145,\n", + " 0.10062930161995226,\n", + " 0.18592768458263148,\n", + "][1:]\n", "\n", "print(\"4-qubit BeH Hamiltonian (electronic, Bravyi-Kitaev mapping).\")\n", "print(f\"Number of qubits: {len(paulis[0])}\")\n", @@ -500,7 +558,9 @@ "print(f\"Estimated expectation: {e_estimated:.6f}\")\n", "print(f\"Estimated standard error: {error_estimate:.6f}\")\n", "\n", - "print(f\"Actual difference: {abs(e_exact - e_estimated):.6f} ({100*abs(e_exact - e_estimated)/abs(e_exact):.2f}%)\")\n", + "print(\n", + " f\"Actual difference: {abs(e_exact - e_estimated):.6f} ({100 * abs(e_exact - e_estimated) / abs(e_exact):.2f}%)\"\n", + ")\n", "print(f\"Final shot allocation: {estimator.shots}\")\n", "print(f\"Total shots used: {sum(estimator.shots)}\")" ] @@ -592,34 +652,29 @@ "\n", "# Run comparison\n", "num_runs = 50\n", - "results = {\n", - " 'Random': [],\n", - " 'Uniform': [],\n", - " 'Weighted': [],\n", - " 'Adaptive': [] \n", - "}\n", + "results = {\"Random\": [], \"Uniform\": [], \"Weighted\": [], \"Adaptive\": []}\n", "\n", "print(f\"Running {num_runs} trials for each strategy...\")\n", "for i in tqdm(range(num_runs)):\n", " # Reset the allocator every time so that we don't take advantage of prior measurement knowledge\n", " estimator.reset()\n", - " \n", - " results['Adaptive'].append(\n", + "\n", + " results[\"Adaptive\"].append(\n", " estimator.expectation_from_measurements(\n", " run_adaptive_allocation(device, circuit, estimator, shots_per_round, num_rounds)\n", " )\n", " )\n", - " results['Uniform'].append(\n", + " results[\"Uniform\"].append(\n", " estimator.expectation_from_measurements(\n", " run_fixed_allocation(device, circuit, estimator, uniform_shots)\n", " )\n", " )\n", - " results['Random'].append(\n", + " results[\"Random\"].append(\n", " estimator.expectation_from_measurements(\n", " run_fixed_allocation(device, circuit, estimator, random_shots)\n", " )\n", " )\n", - " results['Weighted'].append(\n", + " results[\"Weighted\"].append(\n", " estimator.expectation_from_measurements(\n", " run_fixed_allocation(device, circuit, estimator, weighted_shots)\n", " )\n", @@ -693,14 +748,9 @@ "# Plot results with separate subplots (squashed aspect ratio)\n", "fig, axes = plt.subplots(4, 1, figsize=(10, 6), sharex=True)\n", "\n", - "colors = {\n", - " 'Random': 'red', \n", - " 'Uniform': 'orange',\n", - " 'Weighted': 'blue',\n", - " 'Adaptive': 'green' \n", - "}\n", + "colors = {\"Random\": \"red\", \"Uniform\": \"orange\", \"Weighted\": \"blue\", \"Adaptive\": \"green\"}\n", "\n", - "strategies = ['Random', 'Uniform', 'Weighted', 'Adaptive']\n", + "strategies = [\"Random\", \"Uniform\", \"Weighted\", \"Adaptive\"]\n", "\n", "# First pass: calculate all histograms to find the maximum bar height\n", "bins = np.arange(0.0, 0.05, 0.001)\n", @@ -716,35 +766,44 @@ "for i, strategy in enumerate(strategies):\n", " values = results[strategy]\n", " errors = np.abs(np.array(values) - e_exact)\n", - " \n", + "\n", " # Plot histogram in the corresponding subplot\n", - " axes[i].hist(errors, bins=bins, \n", - " color=colors[strategy], alpha=0.7, edgecolor='black', linewidth=0.5,\n", - " label=strategy)\n", - " \n", + " axes[i].hist(\n", + " errors,\n", + " bins=bins,\n", + " color=colors[strategy],\n", + " alpha=0.7,\n", + " edgecolor=\"black\",\n", + " linewidth=0.5,\n", + " label=strategy,\n", + " )\n", + "\n", " # Add statistics as legend\n", " mean_error = np.mean(errors)\n", " std_error = np.std(errors)\n", - " \n", - " axes[i].set_ylabel('Frequency')\n", + "\n", + " axes[i].set_ylabel(\"Frequency\")\n", " axes[i].grid(True, alpha=0.3)\n", - " \n", + "\n", " # Set aspect ratio and y-axis limits\n", - " axes[i].set_aspect(aspect='auto')\n", + " axes[i].set_aspect(aspect=\"auto\")\n", " axes[i].set_ylim(0, max_height * 1.05) # Add 5% padding at top\n", - " \n", + "\n", " # Set integer y-ticks\n", " axes[i].yaxis.set_major_locator(MaxNLocator(integer=True))\n", - " \n", + "\n", " # Add legend with strategy name and statistics\n", - " axes[i].legend([f'{strategy} (Mean: {mean_error:.6f}, Std: {std_error:.6f})'], \n", - " loc='upper right', framealpha=0.9)\n", + " axes[i].legend(\n", + " [f\"{strategy} (Mean: {mean_error:.6f}, Std: {std_error:.6f})\"],\n", + " loc=\"upper right\",\n", + " framealpha=0.9,\n", + " )\n", "\n", "# Set common x-label only on the bottom subplot\n", - "axes[-1].set_xlabel('Absolute Error')\n", + "axes[-1].set_xlabel(\"Absolute Error\")\n", "\n", "# Add overall title with more space\n", - "fig.suptitle('Distribution of Estimation Errors by Strategy', fontsize=16, y=0.98)\n", + "fig.suptitle(\"Distribution of Estimation Errors by Strategy\", fontsize=16, y=0.98)\n", "\n", "plt.tight_layout()\n", "plt.subplots_adjust(top=0.93) # Add space between suptitle and subplots\n", @@ -767,35 +826,46 @@ "def visualize_shot_allocation_comparison(strategies, allocations, total_shots):\n", " \"\"\"\n", " Visualize different shot allocation strategies for comparison.\n", - " \n", + "\n", " Args:\n", " strategies (list): Names of the strategies to compare\n", " allocations (list): List of shot allocations for each strategy\n", " total_shots (int): Total number of shots used\n", " \"\"\"\n", " plt.figure(figsize=(12, 6))\n", - " \n", + "\n", " # Create a bar chart for each strategy\n", " x = np.arange(len(allocations[0]))\n", " width = 0.8 / len(strategies)\n", - " \n", + "\n", " for i, (strategy, allocation) in enumerate(zip(strategies, allocations)):\n", - " plt.bar(x + i*width - 0.4 + width/2, allocation, width, \n", - " label=strategy, alpha=0.7, color = colors[strategy])\n", - " \n", - " plt.xlabel('Measurement Group')\n", - " plt.ylabel('Number of Shots')\n", - " plt.title(f'Comparison of Shot Allocation Strategies (Total: {total_shots} shots)')\n", - " plt.xticks(x, [f'Group {i+1}' for i in x])\n", + " plt.bar(\n", + " x + i * width - 0.4 + width / 2,\n", + " allocation,\n", + " width,\n", + " label=strategy,\n", + " alpha=0.7,\n", + " color=colors[strategy],\n", + " )\n", + "\n", + " plt.xlabel(\"Measurement Group\")\n", + " plt.ylabel(\"Number of Shots\")\n", + " plt.title(f\"Comparison of Shot Allocation Strategies (Total: {total_shots} shots)\")\n", + " plt.xticks(x, [f\"Group {i + 1}\" for i in x])\n", " plt.legend()\n", " plt.grid(True, alpha=0.3)\n", - " \n", + "\n", " # Add percentages on top of each bar\n", " for i, (strategy, allocation) in enumerate(zip(strategies, allocations)):\n", " for j, shots in enumerate(allocation):\n", " percentage = 100 * shots / total_shots\n", - " plt.text(j + i*width - 0.4 + width/2, shots + 5, \n", - " f'{percentage:.1f}%', ha='center', fontsize=8)" + " plt.text(\n", + " j + i * width - 0.4 + width / 2,\n", + " shots + 5,\n", + " f\"{percentage:.1f}%\",\n", + " ha=\"center\",\n", + " fontsize=8,\n", + " )" ] }, { @@ -815,7 +885,11 @@ } ], "source": [ - "visualize_shot_allocation_comparison([strategy for strategy in results.keys()], [random_shots, uniform_shots, weighted_shots, estimator.shots], sum(uniform_shots))" + "visualize_shot_allocation_comparison(\n", + " [strategy for strategy in results.keys()],\n", + " [random_shots, uniform_shots, weighted_shots, estimator.shots],\n", + " sum(uniform_shots),\n", + ")" ] }, { diff --git a/notebooks/advanced_algorithms/adaptive_shot_allocation/adaptive_allocation_notebook_helpers.py b/notebooks/advanced_algorithms/adaptive_shot_allocation/adaptive_allocation_notebook_helpers.py index dd2299e8..f1f3858a 100644 --- a/notebooks/advanced_algorithms/adaptive_shot_allocation/adaptive_allocation_notebook_helpers.py +++ b/notebooks/advanced_algorithms/adaptive_shot_allocation/adaptive_allocation_notebook_helpers.py @@ -1,4 +1,3 @@ - from typing import List import numpy as np @@ -15,6 +14,7 @@ _localSim = LocalSimulator() + def create_random_state(num_qubits: int = 4) -> Circuit: """ Generate a quantum circuit with random rotations and entanglement. @@ -33,7 +33,7 @@ def create_random_state(num_qubits: int = 4) -> Circuit: # Entangling layer for i in range(num_qubits - 1): - circ.cnot(control=i, target=i+1) + circ.cnot(control=i, target=i + 1) # Second layer of rotations for i in range(num_qubits): @@ -73,10 +73,12 @@ def get_exact_expectation(circuit: Circuit, paulis: List[str], coeffs: List[floa e_exact += c * result.values[0] return e_exact + """ Utilities for allocating measurement shots across different measurement groups. """ + def get_uniform_shots(num_groups: int, total_shots: int) -> List[int]: """ Generate uniform shot allocation across measurement groups. @@ -132,4 +134,3 @@ def get_weighted_shots(cliq: List[List[int]], coeffs: List[float], total_shots: for i in range(remainder): shots[i] += 1 return shots.tolist() - diff --git a/notebooks/textbook/CHSH_Inequality.ipynb b/notebooks/textbook/CHSH_Inequality.ipynb index eeffbfee..b19944d0 100644 --- a/notebooks/textbook/CHSH_Inequality.ipynb +++ b/notebooks/textbook/CHSH_Inequality.ipynb @@ -455,7 +455,7 @@ ], "source": [ "print(\n", - " f\"Estimated cost to run this example: {tracker.qpu_tasks_cost() + tracker.simulator_tasks_cost() :.2f} USD\"\n", + " f\"Estimated cost to run this example: {tracker.qpu_tasks_cost() + tracker.simulator_tasks_cost():.2f} USD\"\n", ")" ] }, diff --git a/notebooks/textbook/Quantum_Counting_Algorithm.ipynb b/notebooks/textbook/Quantum_Counting_Algorithm.ipynb index bb7ec237..f71432d2 100644 --- a/notebooks/textbook/Quantum_Counting_Algorithm.ipynb +++ b/notebooks/textbook/Quantum_Counting_Algorithm.ipynb @@ -2,6 +2,7 @@ "cells": [ { "cell_type": "markdown", + "id": "b7179342-351f-4f11-b9ac-344ab728a9b0", "metadata": {}, "source": [ "# Quantum Counting Algorithm\n", @@ -9,11 +10,11 @@ "The Quantum Counting algorithm, introduced by Brassard, Høyer, and Tapp [1], counts the number of marked items $M$ in an unstructured database of $N = 2^n$ elements. It combines **Grover's search operator** with **Quantum Phase Estimation (QPE)** to achieve a quadratic speedup over classical counting, requiring only $O(\\sqrt{N})$ oracle queries instead of the classical $\\Theta(N)$.\n", "\n", "**Key idea:** The Grover operator $G = D \\cdot O$ has eigenvalues $e^{\\pm i\\theta}$, where $\\theta$ satisfies $\\sin^2(\\theta/2) = M/N$. By applying QPE to $G$, we estimate $\\theta$ and hence determine $M$." - ], - "id": "b7179342-351f-4f11-b9ac-344ab728a9b0" + ] }, { "cell_type": "markdown", + "id": "01fb7ecc-66ee-420b-95fc-196d58d23f07", "metadata": {}, "source": [ "## References\n", @@ -21,12 +22,12 @@ "[[1] G. Brassard, P. Høyer, and A. Tapp, \"Quantum Counting\", Proceedings of ICALP 1998](https://arxiv.org/abs/quant-ph/9805082)\n", "\n", "[[2] M. Nielsen and I. Chuang, Quantum Computation and Quantum Information, Cambridge University Press, 2010](https://www.cambridge.org/highereducation/books/quantum-computation-and-quantum-information/01E10196D0A682A6AEFFEA52D53BE9AE)" - ], - "id": "01fb7ecc-66ee-420b-95fc-196d58d23f07" + ] }, { "cell_type": "code", "execution_count": null, + "id": "b9bdcb62-8bce-4811-8ae2-9597f1340634", "metadata": {}, "outputs": [], "source": [ @@ -44,11 +45,11 @@ ")\n", "\n", "%matplotlib inline" - ], - "id": "b9bdcb62-8bce-4811-8ae2-9597f1340634" + ] }, { "cell_type": "markdown", + "id": "a0df5ef1-1622-403c-8e44-d310d754d177", "metadata": {}, "source": [ "## Background\n", @@ -68,20 +69,20 @@ "The eigenvalues of $G$ are $e^{\\pm i\\theta}$. QPE with $t$ precision (counting) qubits estimates the phase $\\varphi = \\theta/(2\\pi)$ as a $t$-bit fraction $y/2^t$. From $\\varphi$, we recover:\n", "\n", "$$M = N \\cdot \\sin^2(\\pi \\varphi)$$" - ], - "id": "a0df5ef1-1622-403c-8e44-d310d754d177" + ] }, { "cell_type": "markdown", + "id": "1ff75da5-558a-495f-93ff-e586239b9f14", "metadata": {}, "source": [ "## Prepare the Oracle and Grover Operator" - ], - "id": "1ff75da5-558a-495f-93ff-e586239b9f14" + ] }, { "cell_type": "code", "execution_count": null, + "id": "49c4b0e1-8bbc-441c-adec-3be22125a358", "metadata": {}, "outputs": [ { @@ -123,20 +124,20 @@ "# Verify eigenvalues\n", "eigenvalues = np.linalg.eigvals(grover)\n", "print(f\"\\nEigenvalues of G: {np.round(eigenvalues, 4)}\")" - ], - "id": "49c4b0e1-8bbc-441c-adec-3be22125a358" + ] }, { "cell_type": "markdown", + "id": "fee13411-62cb-41a0-91b6-32f2060b65f6", "metadata": {}, "source": [ "## Build and Print the Quantum Counting Circuit" - ], - "id": "fee13411-62cb-41a0-91b6-32f2060b65f6" + ] }, { "cell_type": "code", "execution_count": null, + "id": "d4537c2f-52dc-4126-9a91-26fdf5d0633b", "metadata": {}, "outputs": [ { @@ -189,20 +190,20 @@ "\n", "print(\"\\nQuantum Counting Circuit:\")\n", "print(circ)" - ], - "id": "d4537c2f-52dc-4126-9a91-26fdf5d0633b" + ] }, { "cell_type": "markdown", + "id": "3bc6f5fe-3771-47ce-a6eb-5d8b2d93442a", "metadata": {}, "source": [ "## Run on a Local Simulator" - ], - "id": "3bc6f5fe-3771-47ce-a6eb-5d8b2d93442a" + ] }, { "cell_type": "code", "execution_count": null, + "id": "8a31859a-8bc7-4901-a787-2dafc3c12fc8", "metadata": {}, "outputs": [ { @@ -236,20 +237,18 @@ "\n", "# Get and display results\n", "print(\"\\nQuantum Counting Results:\")\n", - "results = get_quantum_counting_results(\n", - " task, counting_qubits, search_qubits, verbose=True\n", - ")\n", + "results = get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True)\n", "\n", "print(f\"\\n--- Summary ---\")\n", "print(f\"Actual M = {len(marked_states)}\")\n", "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")\n", "print(f\"Absolute error: {abs(len(marked_states) - results['best_estimate']):.4f}\")" - ], - "id": "8a31859a-8bc7-4901-a787-2dafc3c12fc8" + ] }, { "cell_type": "code", "execution_count": null, + "id": "2ef4d059-766f-4045-b637-2b6a87ce64ae", "metadata": {}, "outputs": [ { @@ -265,36 +264,36 @@ ], "source": [ "# Visualize counting register results\n", - "counting_results = results['counting_register_results']\n", + "counting_results = results[\"counting_register_results\"]\n", "sorted_results = sorted(counting_results.items(), key=lambda x: x[1], reverse=True)\n", "\n", "labels = [f\"|{bs}>\" for bs, _ in sorted_results]\n", "values = [c for _, c in sorted_results]\n", "\n", "plt.figure(figsize=(10, 5))\n", - "plt.bar(labels, values, color='steelblue', alpha=0.8)\n", - "plt.xlabel('Counting Register Measurement')\n", - "plt.ylabel('Counts')\n", - "plt.title(f'Quantum Counting Results (N={N}, M={len(marked_states)})')\n", + "plt.bar(labels, values, color=\"steelblue\", alpha=0.8)\n", + "plt.xlabel(\"Counting Register Measurement\")\n", + "plt.ylabel(\"Counts\")\n", + "plt.title(f\"Quantum Counting Results (N={N}, M={len(marked_states)})\")\n", "plt.xticks(rotation=45)\n", "plt.tight_layout()\n", "plt.show()" - ], - "id": "2ef4d059-766f-4045-b637-2b6a87ce64ae" + ] }, { "cell_type": "markdown", + "id": "fa08c609-3033-41de-9cf4-3cc669412740", "metadata": {}, "source": [ "## Example 2: Counting Multiple Marked Items\n", "\n", "Count 2 marked items in an 8-element search space ($N = 8$, $n = 3$)." - ], - "id": "fa08c609-3033-41de-9cf4-3cc669412740" + ] }, { "cell_type": "code", "execution_count": null, + "id": "e8901c56-66f3-4428-89a9-ceee58082bb1", "metadata": {}, "outputs": [ { @@ -331,28 +330,26 @@ "task = run_quantum_counting(circ, device, shots=2000)\n", "\n", "print(\"Quantum Counting Results (N=8, M=2):\")\n", - "results = get_quantum_counting_results(\n", - " task, counting_qubits, search_qubits, verbose=True\n", - ")\n", + "results = get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True)\n", "\n", "print(f\"\\nActual M = {len(marked_states)}\")\n", "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")" - ], - "id": "e8901c56-66f3-4428-89a9-ceee58082bb1" + ] }, { "cell_type": "markdown", + "id": "ba1c59de-2601-4c7b-a9bf-481e5ea5fabf", "metadata": {}, "source": [ "## Example 3: Edge Case — No Marked Items (M = 0)\n", "\n", "When no items are marked, the algorithm should estimate $M \\approx 0$." - ], - "id": "ba1c59de-2601-4c7b-a9bf-481e5ea5fabf" + ] }, { "cell_type": "code", "execution_count": null, + "id": "e1f273c0-bc56-4d13-9f97-ef9f879d3d27", "metadata": {}, "outputs": [ { @@ -387,28 +384,26 @@ "device = LocalSimulator()\n", "task = run_quantum_counting(circ, device, shots=1000)\n", "\n", - "results = get_quantum_counting_results(\n", - " task, counting_qubits, search_qubits, verbose=True\n", - ")\n", + "results = get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True)\n", "\n", "print(f\"\\nActual M = 0\")\n", "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")" - ], - "id": "e1f273c0-bc56-4d13-9f97-ef9f879d3d27" + ] }, { "cell_type": "markdown", + "id": "c224af69-fd26-4997-bcc7-86bb1c35d4f4", "metadata": {}, "source": [ "## Example 4: Edge Case — All Items Marked (M = N)\n", "\n", "When all items are marked, $M = N$." - ], - "id": "c224af69-fd26-4997-bcc7-86bb1c35d4f4" + ] }, { "cell_type": "code", "execution_count": null, + "id": "36cbb24d-a2d5-44b3-8496-42d5c6335473", "metadata": {}, "outputs": [ { @@ -443,28 +438,26 @@ "device = LocalSimulator()\n", "task = run_quantum_counting(circ, device, shots=1000)\n", "\n", - "results = get_quantum_counting_results(\n", - " task, counting_qubits, search_qubits, verbose=True\n", - ")\n", + "results = get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True)\n", "\n", "print(f\"\\nActual M = {N}\")\n", "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")" - ], - "id": "36cbb24d-a2d5-44b3-8496-42d5c6335473" + ] }, { "cell_type": "markdown", + "id": "5d747213-799b-4be7-a5b9-efc3c9bd57a6", "metadata": {}, "source": [ "## [Optional] Run on a QPU or Managed Simulator\n", "\n", "[Include estimated price for running in USD using the [cost tracker](https://docs.aws.amazon.com/braket/latest/developerguide/braket-pricing.html#real-time-cost-tracking).]" - ], - "id": "5d747213-799b-4be7-a5b9-efc3c9bd57a6" + ] }, { "cell_type": "code", "execution_count": null, + "id": "690a8210-747e-4c22-882f-60b516a2f201", "metadata": {}, "outputs": [], "source": [ @@ -472,12 +465,12 @@ "# from braket.tracking import Tracker\n", "\n", "# tracker = Tracker().start()" - ], - "id": "690a8210-747e-4c22-882f-60b516a2f201" + ] }, { "cell_type": "code", "execution_count": null, + "id": "2c70f923-0cce-49ab-a382-1a4c7fd296a8", "metadata": {}, "outputs": [], "source": [ @@ -508,12 +501,12 @@ "# task, counting_qubits, search_qubits, verbose=True\n", "# )\n", "# print(f\"\\nEstimated M ≈ {results['best_estimate']:.4f}\")" - ], - "id": "2c70f923-0cce-49ab-a382-1a4c7fd296a8" + ] }, { "cell_type": "code", "execution_count": null, + "id": "1c2e7121-a3d3-42c7-b334-3ba29785617b", "metadata": {}, "outputs": [], "source": [ @@ -522,16 +515,15 @@ "# print(\n", "# f\"Estimated cost to run this example: {tracker.qpu_tasks_cost() + tracker.simulator_tasks_cost():.2f} USD\"\n", "# )" - ], - "id": "1c2e7121-a3d3-42c7-b334-3ba29785617b" + ] }, { "cell_type": "markdown", + "id": "2ab582fd-c942-4207-a218-9d13fc73317b", "metadata": {}, "source": [ "Note: Charges shown are estimates based on your Amazon Braket simulator and quantum processing unit (QPU) task usage. Estimated charges shown may differ from your actual charges. Estimated charges do not factor in any discounts or credits, and you may experience additional charges based on your use of other services such as Amazon Elastic Compute Cloud (Amazon EC2)." - ], - "id": "2ab582fd-c942-4207-a218-9d13fc73317b" + ] } ], "metadata": { diff --git a/src/braket/experimental/algorithms/adaptive_shot_allocation/adaptive_allocator.py b/src/braket/experimental/algorithms/adaptive_shot_allocation/adaptive_allocator.py index f1fd03b8..0780e281 100644 --- a/src/braket/experimental/algorithms/adaptive_shot_allocation/adaptive_allocator.py +++ b/src/braket/experimental/algorithms/adaptive_shot_allocation/adaptive_allocator.py @@ -33,7 +33,7 @@ def commute(a: str, b: str, qwc: bool = True) -> bool: Raises: ValueError: If the Pauli strigns are of different length. """ - if len(a)!=len(b): + if len(a) != len(b): raise ValueError("Pauli strings must be of the same length.") count = 0 for i in zip(a, b): @@ -42,15 +42,17 @@ def commute(a: str, b: str, qwc: bool = True) -> bool: # Partial functions for specific commutation checks -qwc_commute = partial(commute, qwc=True) # Qubit-wise commutation -gen_commute = partial(commute, qwc=False) # General commutation +qwc_commute = partial(commute, qwc=True) # Qubit-wise commutation +gen_commute = partial(commute, qwc=False) # General commutation # BAYESIAN STATISTICS (closed formulas from Appendix B of arXiv:2110.15339v6) -def term_variance_estimate(term_idx: int, measurements: Union[MeasurementData, None] = None) -> float: +def term_variance_estimate( + term_idx: int, measurements: Union[MeasurementData, None] = None +) -> float: """ - Estimate variance for a single Pauli term. + Estimate variance for a single Pauli term. See Eq 14 in Appendix B of "Adaptive Estimation of Quantum Observables (arXiv:2110.15339v6) Args: @@ -64,10 +66,12 @@ def term_variance_estimate(term_idx: int, measurements: Union[MeasurementData, N if measurements: x0 = measurements[term_idx][term_idx][(1, 1)] x1 = measurements[term_idx][term_idx][(-1, -1)] - return 4*((x0+1)*(x1+1))/((x0+x1+2)*(x0+x1+3)) + return 4 * ((x0 + 1) * (x1 + 1)) / ((x0 + x1 + 2) * (x0 + x1 + 3)) -def terms_covariance_estimate(i: int, j: int, measurements: Union[MeasurementData, None] = None) -> float: +def terms_covariance_estimate( + i: int, j: int, measurements: Union[MeasurementData, None] = None +) -> float: """ Estimate covariance between two Pauli terms. See Eq 25-6 in Appendix B of "Adaptive Estimation of Quantum Observables (arXiv:2110.15339v6) @@ -93,14 +97,17 @@ def terms_covariance_estimate(i: int, j: int, measurements: Union[MeasurementDat xy11 = measurements[i][j][(-1, -1)] # Calculate prior probabilities - p00 = 4*((x0+1)*(y0+1))/((x0+x1+2)*(y0+y1+2)) - p01 = 4*((x0+1)*(y1+1))/((x0+x1+2)*(y0+y1+2)) - p10 = 4*((x1+1)*(y0+1))/((x0+x1+2)*(y0+y1+2)) - p11 = 4*((x1+1)*(y1+1))/((x0+x1+2)*(y0+y1+2)) + p00 = 4 * ((x0 + 1) * (y0 + 1)) / ((x0 + x1 + 2) * (y0 + y1 + 2)) + p01 = 4 * ((x0 + 1) * (y1 + 1)) / ((x0 + x1 + 2) * (y0 + y1 + 2)) + p10 = 4 * ((x1 + 1) * (y0 + 1)) / ((x0 + x1 + 2) * (y0 + y1 + 2)) + p11 = 4 * ((x1 + 1) * (y1 + 1)) / ((x0 + x1 + 2) * (y0 + y1 + 2)) # Return Bayesian covariance estimate - return 4*((xy00+p00)*(xy11+p11) - (xy01+p01)*(xy10+p10)) / \ - ((xy00+xy01+xy10+xy11+4)*(xy00+xy01+xy10+xy11+5)) + return ( + 4 + * ((xy00 + p00) * (xy11 + p11) - (xy01 + p01) * (xy10 + p10)) + / ((xy00 + xy01 + xy10 + xy11 + 4) * (xy00 + xy01 + xy10 + xy11 + 5)) + ) class AdaptiveShotAllocator: @@ -156,11 +163,10 @@ def __init__(self, paulis: List[str], coeffs: List[float]) -> None: raise ValueError("Number of Paulis must match coefficients") # Validate Pauli strings - valid_chars = set('IXYZ') + valid_chars = set("IXYZ") for pauli in paulis: if not set(pauli).issubset(valid_chars): - raise ValueError( - f"Invalid Pauli string: {pauli}. Must only contain I, X, Y, or Z") + raise ValueError(f"Invalid Pauli string: {pauli}. Must only contain I, X, Y, or Z") self.paulis = paulis self.coeffs = coeffs self.graph = self._generate_graph() @@ -179,9 +185,10 @@ def reset(self): - Updates graph weights to initial values """ # Initialize measurement counts for all term pairs - self.measurements = [[{(1, 1): 0, (1, -1): 0, (-1, 1): 0, (-1, -1): 0} - for _ in range(self.num_terms)] - for _ in range(self.num_terms)] + self.measurements = [ + [{(1, 1): 0, (1, -1): 0, (-1, 1): 0, (-1, -1): 0} for _ in range(self.num_terms)] + for _ in range(self.num_terms) + ] self.shots = None # Clear shot allocation history self._update_graph_weights() # Reset graph weights @@ -201,7 +208,9 @@ def _generate_graph(self, commute: Callable[[str, str], bool] = qwc_commute): Edges are added between terms that commute according to the provided function. """ if commute != qwc_commute: - warnings.warn("Braket only supports simultaneous measurement of qubit-wise commuting operators.") + warnings.warn( + "Braket only supports simultaneous measurement of qubit-wise commuting operators." + ) # Create graph and add nodes with Pauli string labels self.graph = nx.Graph() @@ -229,8 +238,9 @@ def _partition_graph(self): _, cliq = approximation.clique_removal(self.graph) self.cliq = [sorted(i) for i in cliq] # Sort cliques for consistency - def visualize_graph(self, node_size: int = 1230, font_size: int = 10, - show_cliques: bool = True) -> None: + def visualize_graph( + self, node_size: int = 1230, font_size: int = 10, show_cliques: bool = True + ) -> None: """ Visualize the graph with colored edges based on clique membership. @@ -242,15 +252,17 @@ def visualize_graph(self, node_size: int = 1230, font_size: int = 10, """ # Generate random colors for each clique - cliq_colors = ["#"+"".join([hex(random.randint(0, 255))[2:].zfill(2) - for _ in range(3)]) for _ in self.cliq] + cliq_colors = [ + "#" + "".join([hex(random.randint(0, 255))[2:].zfill(2) for _ in range(3)]) + for _ in self.cliq + ] # Build edge list and colors if show_cliques: el = [] ec = [] for e in self.graph.edges: - for i,c in enumerate(self.cliq): + for i, c in enumerate(self.cliq): if (e[0] in c) and (e[1] in c): el.append(e) ec.append(cliq_colors[i]) @@ -258,23 +270,32 @@ def visualize_graph(self, node_size: int = 1230, font_size: int = 10, else: el = list(self.graph.edges) # Use gray for all edges when showing full graph - ec = ['gray' for _ in el] + ec = ["gray" for _ in el] # Create layout pos = nx.circular_layout(self.graph) # Draw the graph plt.figure(figsize=(10, 10)) - nx.draw(self.graph, pos=pos, with_labels=False, - node_color='white', node_size=node_size, - edgelist=el, edge_color=ec) + nx.draw( + self.graph, + pos=pos, + with_labels=False, + node_color="white", + node_size=node_size, + edgelist=el, + edge_color=ec, + ) # Add labels - nx.draw_networkx_labels(self.graph, pos, - labels=nx.get_node_attributes( - self.graph, 'label'), - font_size=font_size, font_color="black", - font_family="Times") + nx.draw_networkx_labels( + self.graph, + pos, + labels=nx.get_node_attributes(self.graph, "label"), + font_size=font_size, + font_color="black", + font_family="Times", + ) # Set edge colors ax = plt.gca() @@ -299,9 +320,12 @@ def _update_graph_weights(self) -> None: # Base weight from coefficients weight = self.coeffs[i] * self.coeffs[j] # Multiply by variance/covariance estimate - weight *= (term_variance_estimate(i, measurements) if i == j - else terms_covariance_estimate(i, j, measurements)) - self.graph[i][j]['weight'] = weight + weight *= ( + term_variance_estimate(i, measurements) + if i == j + else terms_covariance_estimate(i, j, measurements) + ) + self.graph[i][j]["weight"] = weight def incremental_shot_allocation(self, num_shots: int) -> List[int]: """ @@ -337,13 +361,14 @@ def incremental_shot_allocation(self, num_shots: int) -> List[int]: current_shots = self.shots if self.shots else [0 for c in self.cliq] # Calculate weighted covariance matrix for error estimates - weighted_covariance = nx.adjacency_matrix( - self.graph, weight="weight").toarray() + weighted_covariance = nx.adjacency_matrix(self.graph, weight="weight").toarray() # Initialize error estimates for each clique using current shots # Error = sqrt(sum of covariances) / number of shots - clique_error = [np.sqrt(weighted_covariance[c, c].sum())/(current_shots[e] or not current_shots[e]) - for e, c in enumerate(self.cliq)] + clique_error = [ + np.sqrt(weighted_covariance[c, c].sum()) / (current_shots[e] or not current_shots[e]) + for e, c in enumerate(self.cliq) + ] # Allocate shots one at a time for _ in range(num_shots): @@ -356,8 +381,7 @@ def incremental_shot_allocation(self, num_shots: int) -> List[int]: # Update error estimate for the chosen clique # New error = Old error * (n/(n+1)) where n+1 is the updated shot count. total_shots = current_shots[cliq_id] + proposed_allocation[cliq_id] - clique_error[cliq_id] *= ((total_shots-1) - or not (total_shots-1))/(total_shots) + clique_error[cliq_id] *= ((total_shots - 1) or not (total_shots - 1)) / (total_shots) return proposed_allocation @@ -379,18 +403,23 @@ def error_estimate(self) -> float: ValueError: If graph weights have not been properly initialized """ # Get weighted covariance matrix - weighted_covariance = nx.adjacency_matrix( - self.graph, weight="weight").toarray() + weighted_covariance = nx.adjacency_matrix(self.graph, weight="weight").toarray() # Sum variance contributions from each clique - variance_estimate = sum([(weighted_covariance[c, c].sum())/(self.shots[e] or not self.shots[e]) - for e, c in enumerate(self.cliq)]) + variance_estimate = sum( + [ + (weighted_covariance[c, c].sum()) / (self.shots[e] or not self.shots[e]) + for e, c in enumerate(self.cliq) + ] + ) return np.sqrt(variance_estimate) - def expectation_from_measurements(self, measurements: Union[MeasurementData, None] = None) -> float: + def expectation_from_measurements( + self, measurements: Union[MeasurementData, None] = None + ) -> float: """ - Calculate the energy expectation value from measurement results + Calculate the energy expectation value from measurement results for the different Pauli string observables. For each Pauli term, computes

= (N++ - N--)/N_total where: @@ -414,17 +443,15 @@ def expectation_from_measurements(self, measurements: Union[MeasurementData, Non expectation = 0.0 for i in range(len(self.coeffs)): # Verify no invalid measurements - assert measurements[i][i][( - 1, -1)] == 0, "Invalid measurement detected: (+1,-1)" - assert measurements[i][i][(-1, 1) - ] == 0, "Invalid measurement detected: (-1,+1)" + assert measurements[i][i][(1, -1)] == 0, "Invalid measurement detected: (+1,-1)" + assert measurements[i][i][(-1, 1)] == 0, "Invalid measurement detected: (-1,+1)" # Calculate expectation for this term - term_shots = measurements[i][i][( - 1, 1)] + measurements[i][i][(-1, -1)] + term_shots = measurements[i][i][(1, 1)] + measurements[i][i][(-1, -1)] if term_shots: term_expect = ( - measurements[i][i][(1, 1)] - measurements[i][i][(-1, -1)]) / term_shots + measurements[i][i][(1, 1)] - measurements[i][i][(-1, -1)] + ) / term_shots expectation += self.coeffs[i] * term_expect return expectation @@ -447,13 +474,11 @@ def _validate_measurements(self, measurements: MeasurementData) -> bool: Raises: AssertionError: If any validation check fails """ - assert len( - measurements) == self.num_terms, "Wrong number of measurement records" + assert len(measurements) == self.num_terms, "Wrong number of measurement records" for c in self.cliq: # Get total shots for this clique - m_cliq = (measurements[c[0]][c[0]][(1, 1)] + - measurements[c[0]][c[0]][(-1, -1)]) + m_cliq = measurements[c[0]][c[0]][(1, 1)] + measurements[c[0]][c[0]][(-1, -1)] # Check consistency within clique for i in c: @@ -463,25 +488,31 @@ def _validate_measurements(self, measurements: MeasurementData) -> bool: assert v >= 0, "Measurement counts should not be negative" # Measurements should be symmetric - assert measurements[i][j][(1,1)]==measurements[j][i][(1,1)],\ - "Measurement should be symmetric" - assert measurements[i][j][(-1,-1)]==measurements[j][i][(-1,-1)],\ - "Measurement should be symmetric" - assert measurements[i][j][(1,-1)]==measurements[j][i][(-1,1)],\ - "Measurement should be symmetric" - assert measurements[i][j][(-1,1)]==measurements[j][i][(1,-1)],\ - "Measurement should be symmetric" + assert measurements[i][j][(1, 1)] == measurements[j][i][(1, 1)], ( + "Measurement should be symmetric" + ) + assert measurements[i][j][(-1, -1)] == measurements[j][i][(-1, -1)], ( + "Measurement should be symmetric" + ) + assert measurements[i][j][(1, -1)] == measurements[j][i][(-1, 1)], ( + "Measurement should be symmetric" + ) + assert measurements[i][j][(-1, 1)] == measurements[j][i][(1, -1)], ( + "Measurement should be symmetric" + ) # All pairs in clique should have same total measurements - assert m_cliq == sum(measurements[i][j].values()), \ - (f"The number of times {i} and {j} were measured together should be " - "equal to the number of measurements of their clique.") + assert m_cliq == sum(measurements[i][j].values()), ( + f"The number of times {i} and {j} were measured together should be " + "equal to the number of measurements of their clique." + ) # Diagonal elements should not have invalid combinations if i == j: - assert measurements[i][i][(1, -1)] == measurements[i][i][(-1, 1)] == 0, \ - ("A measurement of a single term can only contribute to the " - "(1,1) or (-1,-1) counts.") + assert measurements[i][i][(1, -1)] == measurements[i][i][(-1, 1)] == 0, ( + "A measurement of a single term can only contribute to the " + "(1,1) or (-1,-1) counts." + ) return True def shots_from_measurements(self, measurements: MeasurementData) -> List[int]: diff --git a/src/braket/experimental/algorithms/adaptive_shot_allocation/adaptive_allocator_braket_helpers.py b/src/braket/experimental/algorithms/adaptive_shot_allocation/adaptive_allocator_braket_helpers.py index 6cb8017a..ea8f2125 100644 --- a/src/braket/experimental/algorithms/adaptive_shot_allocation/adaptive_allocator_braket_helpers.py +++ b/src/braket/experimental/algorithms/adaptive_shot_allocation/adaptive_allocator_braket_helpers.py @@ -1,5 +1,5 @@ """ -Helper functions to handle quantum measurements and adaptive shot allocation +Helper functions to handle quantum measurements and adaptive shot allocation experiments on Amazon Braket. """ @@ -13,6 +13,7 @@ MeasurementData, ) + def observable_from_string(pauli_string: str) -> Observable: """ Convert Pauli string to Braket observable. @@ -23,15 +24,15 @@ def observable_from_string(pauli_string: str) -> Observable: Returns: Observable: Corresponding Braket observable """ - gates = {"I": Observable.I, "X": Observable.X, - "Y": Observable.Y, "Z": Observable.Z} + gates = {"I": Observable.I, "X": Observable.X, "Y": Observable.Y, "Z": Observable.Z} return Observable.TensorProduct([gates[i[1]](i[0]) for i in enumerate(pauli_string)]) + def run_fixed_allocation( device: Union[LocalSimulator, AwsDevice], circuit: Circuit, estimator: AdaptiveShotAllocator, - shot_allocation: List[int] + shot_allocation: List[int], ) -> MeasurementData: """ Run experiment with a specific shot allocation. @@ -45,7 +46,7 @@ def run_fixed_allocation( Returns: MeasurementData: Measurement outcomes for each term pair """ - + # Step 1. Submit all tasks. tasks = {} for c_idx, c in enumerate(estimator.cliq): @@ -54,41 +55,40 @@ def run_fixed_allocation( measurement_circ = circuit.copy() for p in c: - measurement_circ.sample( - observable_from_string(estimator.paulis[p])) + measurement_circ.sample(observable_from_string(estimator.paulis[p])) + + tasks[c_idx] = device.run(measurement_circ, shots=shot_allocation[c_idx]) - tasks[c_idx] = device.run( - measurement_circ, shots=shot_allocation[c_idx]) - # Step 2. Post-process results. - measurements = [[{(1, 1): 0, (1, -1): 0, (-1, 1): 0, (-1, -1): 0} - for _ in range(len(estimator.paulis))] - for _ in range(len(estimator.paulis))] - - while(tasks): + measurements = [ + [{(1, 1): 0, (1, -1): 0, (-1, 1): 0, (-1, -1): 0} for _ in range(len(estimator.paulis))] + for _ in range(len(estimator.paulis)) + ] + + while tasks: task_to_process = None - + for c_idx in tasks: # Check task status state = tasks[c_idx].state() - assert state in ["CREATED", "QUEUED", "RUNNING", "COMPLETED"], \ + assert state in ["CREATED", "QUEUED", "RUNNING", "COMPLETED"], ( f"Encountered quantum task failure (status: {state})." + ) if state == "COMPLETED": task_to_process = c_idx break - + if task_to_process is None: continue - + # Task is ready for post-processing result = tasks[task_to_process].result() c = estimator.cliq[task_to_process] for i_idx, i in enumerate(c): for j_idx, j in enumerate(c): for s in range(len(result.values[i_idx])): - measurements[i][j][(result.values[i_idx][s], - result.values[j_idx][s])] += 1 + measurements[i][j][(result.values[i_idx][s], result.values[j_idx][s])] += 1 # Remove task from the queue tasks.pop(task_to_process) @@ -101,7 +101,7 @@ def run_adaptive_allocation( estimator: AdaptiveShotAllocator, shots_per_round: int, num_rounds: int, - verbose: bool = False + verbose: bool = False, ) -> MeasurementData: """ Run adaptive shot allocation process. @@ -118,14 +118,12 @@ def run_adaptive_allocation( MeasurementData: Final measurement outcomes """ if verbose: - print( - f"Running {num_rounds} rounds with {shots_per_round} shots each:") + print(f"Running {num_rounds} rounds with {shots_per_round} shots each:") for i in range(num_rounds): if verbose: - print(f"Round {i+1}/{num_rounds}...") + print(f"Round {i + 1}/{num_rounds}...") shots_to_run = estimator.incremental_shot_allocation(shots_per_round) - new_measurements = run_fixed_allocation( - device, circuit, estimator, shots_to_run) + new_measurements = run_fixed_allocation(device, circuit, estimator, shots_to_run) estimator.update_measurements(new_measurements) return estimator.measurements diff --git a/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py b/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py index f72d1633..f56651f3 100644 --- a/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py +++ b/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py @@ -33,7 +33,6 @@ from braket.tasks import QuantumTask - def build_oracle_matrix(n_qubits: int, marked_states: List[int]) -> np.ndarray: """Build a diagonal oracle matrix that flips the phase of marked states. @@ -209,7 +208,6 @@ def quantum_counting( qc_circ.h(search_qubits) # Controlled-G^(2^k) - n_counting = len(counting_qubits) for ii, qubit in enumerate(reversed(counting_qubits)): power = 2**ii g_power = np.linalg.matrix_power(grover_matrix, power) @@ -279,8 +277,7 @@ def get_quantum_counting_results( for key in measurement_counts.keys(): counting_bits = key[:n_counting] counting_register_results[counting_bits] = ( - counting_register_results.get(counting_bits, 0) - + measurement_counts[key] + counting_register_results.get(counting_bits, 0) + measurement_counts[key] ) # Convert counting register bitstrings to phase estimates and M estimates diff --git a/test/unit_tests/braket/experimental/algorithms/adaptive_shot_allocation/test_adaptive_allocator.py b/test/unit_tests/braket/experimental/algorithms/adaptive_shot_allocation/test_adaptive_allocator.py index 3d02a80a..9a52d7e2 100644 --- a/test/unit_tests/braket/experimental/algorithms/adaptive_shot_allocation/test_adaptive_allocator.py +++ b/test/unit_tests/braket/experimental/algorithms/adaptive_shot_allocation/test_adaptive_allocator.py @@ -1,13 +1,17 @@ -import pytest -import networkx as nx import unittest +from unittest.mock import patch + +import networkx as nx +import pytest from braket.experimental.algorithms.adaptive_shot_allocation.adaptive_allocator import ( - commute, qwc_commute, gen_commute, - term_variance_estimate, terms_covariance_estimate, - AdaptiveShotAllocator + AdaptiveShotAllocator, + commute, + gen_commute, + qwc_commute, + term_variance_estimate, + terms_covariance_estimate, ) -from unittest.mock import patch # Fixtures for common test setups @@ -30,14 +34,15 @@ def mock_measurements_2terms(): return [ [ {(1, 1): 5, (1, -1): 0, (-1, 1): 0, (-1, -1): 5}, - {(1, 1): 3, (1, -1): 2, (-1, 1): 1, (-1, -1): 4} + {(1, 1): 3, (1, -1): 2, (-1, 1): 1, (-1, -1): 4}, ], [ {(1, 1): 3, (1, -1): 1, (-1, 1): 2, (-1, -1): 4}, - {(1, 1): 6, (1, -1): 0, (-1, 1): 0, (-1, -1): 4} - ] + {(1, 1): 6, (1, -1): 0, (-1, 1): 0, (-1, -1): 4}, + ], ] + # 1. Tests for Helper Functions @@ -77,13 +82,12 @@ def test_partial_commute_functions(): def test_term_variance_estimate(): # Test with no measurements (prior only) # With no measurements, the formula gives 4*(1*1)/(2*3) = 4/6 = 2/3 - assert abs(term_variance_estimate(0) - 2/3) < 1e-10 + assert abs(term_variance_estimate(0) - 2 / 3) < 1e-10 # Test with mock measurements mock_measurements = [[{(1, 1): 10, (1, -1): 0, (-1, 1): 0, (-1, -1): 5}]] - expected_variance = 4 * ((10+1) * (5+1)) / ((10+5+2) * (10+5+3)) - assert abs(term_variance_estimate( - 0, mock_measurements) - expected_variance) < 1e-10 + expected_variance = 4 * ((10 + 1) * (5 + 1)) / ((10 + 5 + 2) * (10 + 5 + 3)) + assert abs(term_variance_estimate(0, mock_measurements) - expected_variance) < 1e-10 def test_terms_covariance_estimate(): @@ -94,19 +98,18 @@ def test_terms_covariance_estimate(): # Test with mock measurements mock_measurements = [ [{(1, 1): 5, (1, -1): 0, (-1, 1): 0, (-1, -1): 5}], - [{(1, 1): 7, (1, -1): 0, (-1, 1): 0, (-1, -1): 3}] + [{(1, 1): 7, (1, -1): 0, (-1, 1): 0, (-1, -1): 3}], ] # Add cross-measurements - mock_measurements[0].append( - {(1, 1): 4, (1, -1): 1, (-1, 1): 2, (-1, -1): 3}) - mock_measurements[1].insert( - 0, {(1, 1): 4, (1, -1): 2, (-1, 1): 1, (-1, -1): 3}) + mock_measurements[0].append({(1, 1): 4, (1, -1): 1, (-1, 1): 2, (-1, -1): 3}) + mock_measurements[1].insert(0, {(1, 1): 4, (1, -1): 2, (-1, 1): 1, (-1, -1): 3}) # Calculate covariance result = terms_covariance_estimate(0, 1, mock_measurements) assert isinstance(result, float) assert -1.0 <= result <= 1.0 # Covariance should be in this range + # 2. Tests for AdaptiveShotAllocator Class @@ -139,9 +142,11 @@ def test_reset_method(simple_allocator): # Reset and check state simple_allocator.reset() assert simple_allocator.shots is None - assert all(all(outcome == 0 for outcome in simple_allocator.measurements[i][j].values()) - for i in range(simple_allocator.num_terms) - for j in range(simple_allocator.num_terms)) + assert all( + all(outcome == 0 for outcome in simple_allocator.measurements[i][j].values()) + for i in range(simple_allocator.num_terms) + for j in range(simple_allocator.num_terms) + ) def test_generate_graph(): @@ -163,8 +168,7 @@ def test_generate_graph(): def test_partition_graph(): # Create a simple graph with known clique structure - allocator = AdaptiveShotAllocator( - ["II", "IX", "IZ", "ZI"], [1.0, 1.0, 1.0, 1.0]) + allocator = AdaptiveShotAllocator(["II", "IX", "IZ", "ZI"], [1.0, 1.0, 1.0, 1.0]) # II, IX, ZI should form one clique (all commute with each other) # IZ should be in a separate clique @@ -195,8 +199,7 @@ def test_error_estimate(simple_allocator): simple_allocator.shots = [10, 15] # Mock measurements to update graph weights - mock_measurements = [ - [{(1, 1): 6, (1, -1): 0, (-1, 1): 0, (-1, -1): 4}] * 2] * 2 + mock_measurements = [[{(1, 1): 6, (1, -1): 0, (-1, 1): 0, (-1, -1): 4}] * 2] * 2 simple_allocator.update_measurements(mock_measurements) # Calculate error estimate @@ -228,12 +231,12 @@ def test_expectation_from_measurements(): mock_measurements = [ [ {(1, 1): 8, (1, -1): 0, (-1, 1): 0, (-1, -1): 2}, - {(1, 1): 0, (1, -1): 0, (-1, 1): 0, (-1, -1): 0} + {(1, 1): 0, (1, -1): 0, (-1, 1): 0, (-1, -1): 0}, ], [ {(1, 1): 0, (1, -1): 0, (-1, 1): 0, (-1, -1): 0}, - {(1, 1): 0, (1, -1): 0, (-1, 1): 0, (-1, -1): 0} - ] + {(1, 1): 0, (1, -1): 0, (-1, 1): 0, (-1, -1): 0}, + ], ] # Expected: 0.5 * 0.6 + (-0.3) * (0.0) = 0.3 + 0.0 = 0.0 @@ -250,22 +253,18 @@ def test_validate_measurements(): valid_measurements = [ [ {(1, 1): 5, (1, -1): 0, (-1, 1): 0, (-1, -1): 5}, - {(1, 1): 3, (1, -1): 2, (-1, 1): 1, (-1, -1): 4} + {(1, 1): 3, (1, -1): 2, (-1, 1): 1, (-1, -1): 4}, ], [ {(1, 1): 3, (1, -1): 1, (-1, 1): 2, (-1, -1): 4}, - {(1, 1): 6, (1, -1): 0, (-1, 1): 0, (-1, -1): 4} - ] + {(1, 1): 6, (1, -1): 0, (-1, 1): 0, (-1, -1): 4}, + ], ] assert allocator._validate_measurements(valid_measurements) == True # Invalid measurements (wrong size) - invalid_measurements = [ - [ - {(1, 1): 5, (1, -1): 0, (-1, 1): 0, (-1, -1): 5} - ] - ] + invalid_measurements = [[{(1, 1): 5, (1, -1): 0, (-1, 1): 0, (-1, -1): 5}]] with pytest.raises(AssertionError): allocator._validate_measurements(invalid_measurements) @@ -274,12 +273,12 @@ def test_validate_measurements(): invalid_measurements = [ [ {(1, 1): 5, (1, -1): 0, (-1, 1): 0, (-1, -1): 5}, - {(1, 1): 3, (1, -1): 2, (-1, 1): 1, (-1, -1): 3} # Sum is 9, not 10 + {(1, 1): 3, (1, -1): 2, (-1, 1): 1, (-1, -1): 3}, # Sum is 9, not 10 ], [ {(1, 1): 3, (1, -1): 1, (-1, 1): 2, (-1, -1): 4}, - {(1, 1): 6, (1, -1): 0, (-1, 1): 0, (-1, -1): 4} - ] + {(1, 1): 6, (1, -1): 0, (-1, 1): 0, (-1, -1): 4}, + ], ] with pytest.raises(AssertionError): @@ -289,12 +288,12 @@ def test_validate_measurements(): invalid_measurements = [ [ {(1, 1): 5, (1, -1): 0, (-1, 1): 0, (-1, -1): 5}, - {(1, 1): 3, (1, -1): 2, (-1, 1): 1, (-1, -1): 4} + {(1, 1): 3, (1, -1): 2, (-1, 1): 1, (-1, -1): 4}, ], [ {(1, 1): 3, (1, -1): 2, (-1, 1): 1, (-1, -1): 4}, - {(1, 1): 6, (1, -1): 0, (-1, 1): 0, (-1, -1): 4} - ] + {(1, 1): 6, (1, -1): 0, (-1, 1): 0, (-1, -1): 4}, + ], ] with pytest.raises(AssertionError): @@ -304,12 +303,12 @@ def test_validate_measurements(): invalid_measurements = [ [ {(1, 1): 5, (1, -1): 0, (-1, 1): 0, (-1, -1): 5}, - {(1, 1): 3, (1, -1): 4, (-1, 1): -1, (-1, -1): 4} + {(1, 1): 3, (1, -1): 4, (-1, 1): -1, (-1, -1): 4}, ], [ {(1, 1): 3, (1, -1): -1, (-1, 1): 4, (-1, -1): 4}, - {(1, 1): 6, (1, -1): 0, (-1, 1): 0, (-1, -1): 4} - ] + {(1, 1): 6, (1, -1): 0, (-1, 1): 0, (-1, -1): 4}, + ], ] with pytest.raises(AssertionError): @@ -323,20 +322,21 @@ def test_shots_from_measurements(): mock_measurements = [ [ {(1, 1): 5, (1, -1): 0, (-1, 1): 0, (-1, -1): 5}, # 10 shots - {(1, 1): 3, (1, -1): 2, (-1, 1): 1, (-1, -1): 4} + {(1, 1): 3, (1, -1): 2, (-1, 1): 1, (-1, -1): 4}, ], [ {(1, 1): 3, (1, -1): 1, (-1, 1): 2, (-1, -1): 4}, - {(1, 1): 6, (1, -1): 0, (-1, 1): 0, (-1, -1): 4} # 10 shots - ] + {(1, 1): 6, (1, -1): 0, (-1, 1): 0, (-1, -1): 4}, # 10 shots + ], ] shots = allocator.shots_from_measurements(mock_measurements) assert len(shots) == len(allocator.cliq) assert shots[0] == 10 # First clique should have 10 shots + class VisualizationTest(unittest.TestCase): - @patch('matplotlib.pyplot.show') + @patch("matplotlib.pyplot.show") def test_graph(*args): paulis = ["XX", "IZ", "ZI", "YY", "XI"] coeffs = [0.5, 0.3, -0.2, 1.0, 2.0] diff --git a/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py b/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py index bf3e0f85..f6d80b42 100644 --- a/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py +++ b/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py @@ -106,9 +106,7 @@ def test_count_1_of_4(): device = LocalSimulator() task = qc.run_quantum_counting(circ, device, shots=1000) - results = qc.get_quantum_counting_results( - task, counting_qubits, search_qubits, verbose=True - ) + results = qc.get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True) # Best estimate should be close to 1 assert results["best_estimate"] is not None @@ -129,9 +127,7 @@ def test_count_0_of_4(): device = LocalSimulator() task = qc.run_quantum_counting(circ, device, shots=1000) - results = qc.get_quantum_counting_results( - task, counting_qubits, search_qubits, verbose=True - ) + results = qc.get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True) # With no marked items, the most common measurement should yield M ≈ 0 assert results["best_estimate"] is not None @@ -151,9 +147,7 @@ def test_count_4_of_4(): device = LocalSimulator() task = qc.run_quantum_counting(circ, device, shots=1000) - results = qc.get_quantum_counting_results( - task, counting_qubits, search_qubits, verbose=True - ) + results = qc.get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True) # With all items marked, M should be ≈ 4 assert results["best_estimate"] is not None @@ -173,9 +167,7 @@ def test_count_2_of_8(): device = LocalSimulator() task = qc.run_quantum_counting(circ, device, shots=2000) - results = qc.get_quantum_counting_results( - task, counting_qubits, search_qubits, verbose=True - ) + results = qc.get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True) # Best estimate should be close to 2 assert results["best_estimate"] is not None From c8077f65ffa6968a480ff3a6e945898e7f80774a Mon Sep 17 00:00:00 2001 From: axif Date: Wed, 18 Feb 2026 23:51:46 +0600 Subject: [PATCH 4/8] test: add test case for `get_quantum_counting_results` with empty measurement counts. --- .../quantum_counting/test_quantum_counting.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py b/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py index f6d80b42..cffe214d 100644 --- a/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py +++ b/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py @@ -12,6 +12,7 @@ # language governing permissions and limitations under the License. import numpy as np +from unittest.mock import MagicMock from braket.circuits import Circuit from braket.devices import LocalSimulator @@ -207,3 +208,25 @@ def test_counting_results_have_correct_keys(): "search_space_size", } assert set(results.keys()) == expected_keys + + +def test_get_quantum_counting_results_empty_counts(): + """Test get_quantum_counting_results with empty measurement counts.""" + # Mock task and result + mock_task = MagicMock() + mock_result = MagicMock() + mock_result.measurement_counts = {} + mock_task.result.return_value = mock_result + + counting_qubits = [0, 1] + search_qubits = [2] + + # This should trigger the else block setting best_key and best_M to None + results = qc.get_quantum_counting_results(mock_task, counting_qubits, search_qubits) + + assert results["measurement_counts"] == {} + assert results["counting_register_results"] == {} + assert results["phases"] == [] + assert results["estimated_counts"] == [] + assert results["best_estimate"] is None + From ec74cb2f16c739ce839376cab54066427101139e Mon Sep 17 00:00:00 2001 From: axif Date: Sat, 21 Feb 2026 02:04:18 +0600 Subject: [PATCH 5/8] refactor: reimplement Quantum Counting oracle and Grover operator using circuits instead of matrices. --- .../textbook/Quantum_Counting_Algorithm.ipynb | 443 ++++++++++++------ .../algorithms/quantum_counting/__init__.py | 6 +- .../quantum_counting/quantum_counting.py | 200 ++++---- .../quantum_counting/test_quantum_counting.py | 289 ++++++++---- 4 files changed, 609 insertions(+), 329 deletions(-) diff --git a/notebooks/textbook/Quantum_Counting_Algorithm.ipynb b/notebooks/textbook/Quantum_Counting_Algorithm.ipynb index f71432d2..e384164c 100644 --- a/notebooks/textbook/Quantum_Counting_Algorithm.ipynb +++ b/notebooks/textbook/Quantum_Counting_Algorithm.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "b7179342-351f-4f11-b9ac-344ab728a9b0", + "id": "b7179342", "metadata": {}, "source": [ "# Quantum Counting Algorithm\n", @@ -14,7 +14,7 @@ }, { "cell_type": "markdown", - "id": "01fb7ecc-66ee-420b-95fc-196d58d23f07", + "id": "01fb7ecc", "metadata": {}, "source": [ "## References\n", @@ -26,22 +26,21 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "b9bdcb62-8bce-4811-8ae2-9597f1340634", + "execution_count": 1, + "id": "b9bdcb62", "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", + "\n", "from braket.circuits import Circuit\n", "from braket.devices import LocalSimulator\n", - "\n", "from braket.experimental.algorithms.quantum_counting import (\n", - " build_grover_matrix,\n", - " build_oracle_matrix,\n", + " build_grover_circuit,\n", + " build_oracle_circuit,\n", " get_quantum_counting_results,\n", " quantum_counting_circuit,\n", - " run_quantum_counting,\n", ")\n", "\n", "%matplotlib inline" @@ -49,7 +48,7 @@ }, { "cell_type": "markdown", - "id": "a0df5ef1-1622-403c-8e44-d310d754d177", + "id": "a0df5ef1", "metadata": {}, "source": [ "## Background\n", @@ -66,42 +65,62 @@ "\n", "### QPE on the Grover Operator\n", "\n", - "The eigenvalues of $G$ are $e^{\\pm i\\theta}$. QPE with $t$ precision (counting) qubits estimates the phase $\\varphi = \\theta/(2\\pi)$ as a $t$-bit fraction $y/2^t$. From $\\varphi$, we recover:\n", + "Within this 2-dimensional solution subspace, the eigenvalues of $G$ are $e^{\\pm i\\theta}$. QPE with $t$ precision (counting) qubits estimates the phase $\\varphi = \\theta/(2\\pi)$ as a $t$-bit fraction $y/2^t$, where $y$ is the integer readout from the counting register. From our estimate of $\\varphi$, we recover the number of marked items:\n", + "\n", + "$$M = N \\cdot \\sin^2(\\pi \\varphi)$$\n", "\n", - "$$M = N \\cdot \\sin^2(\\pi \\varphi)$$" + "**Note:** The full $N \\times N$ Grover matrix has additional eigenvalues from the orthogonal complement of the solution subspace, but these do not affect the counting algorithm since the initial uniform superposition $|s\\rangle$ lies entirely within the 2D subspace." ] }, { "cell_type": "markdown", - "id": "1ff75da5-558a-495f-93ff-e586239b9f14", + "id": "1ff75da5", "metadata": {}, "source": [ - "## Prepare the Oracle and Grover Operator" + "## Build the Oracle and Grover Circuits\n", + "\n", + "We build the oracle and Grover operator as **circuits** using primitives from the `grovers_search` module:\n", + "- `build_oracle` (from `grovers_search`) constructs a phase-flip oracle for a single basis state\n", + "- `amplify` (from `grovers_search`) constructs the diffusion operator $D = H \\cdot O_0 \\cdot H$\n", + "- `build_oracle_circuit` composes oracles for multiple marked states\n", + "- `build_grover_circuit` combines the oracle and diffusion into the full Grover operator $G$" ] }, { "cell_type": "code", - "execution_count": null, - "id": "49c4b0e1-8bbc-441c-adec-3be22125a358", + "execution_count": 2, + "id": "49c4b0e1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Oracle matrix:\n", - "[[ 1. 0. 0. 0.]\n", - " [ 0. 1. 0. 0.]\n", - " [ 0. 0. 1. 0.]\n", - " [ 0. 0. 0. -1.]]\n", - "\n", - "Grover operator G:\n", - "[[-0.5 0.5 0.5 -0.5]\n", - " [ 0.5 -0.5 0.5 -0.5]\n", - " [ 0.5 0.5 -0.5 -0.5]\n", - " [ 0.5 0.5 0.5 0.5]]\n", + "Oracle circuit (marks state |11>):\n", + "T : │ 0 │ 1 │ 2 │ 3 │ 4 │\n", + " \n", + "q0 : ───────────────●───────────────\n", + " │ \n", + " │ \n", + "q1 : ───────────────●───────────────\n", + " │ \n", + " ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ \n", + "q2 : ─┤ X ├─┤ H ├─┤ X ├─┤ H ├─┤ X ├─\n", + " └───┘ └───┘ └───┘ └───┘ └───┘ \n", + "T : │ 0 │ 1 │ 2 │ 3 │ 4 │\n", "\n", - "Eigenvalues of G: [-1. +0.j 0.5+0.866j 0.5-0.866j -1. +0.j ]\n" + "Grover operator circuit (G = D . O):\n", + "T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │\n", + " ┌───┐ ┌───┐ ┌───┐ ┌───┐ \n", + "q0 : ───────────────●───┤ H ├─┤ X ├───────────────●───┤ X ├─┤ H ├─\n", + " │ └───┘ └───┘ │ └───┘ └───┘ \n", + " │ ┌───┐ ┌───┐ │ ┌───┐ ┌───┐ \n", + "q1 : ───────────────●───┤ H ├─┤ X ├───────────────●───┤ X ├─┤ H ├─\n", + " │ └───┘ └───┘ │ └───┘ └───┘ \n", + " ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ \n", + "q2 : ─┤ X ├─┤ H ├─┤ X ├─┤ H ├─┤ X ├─┤ X ├─┤ H ├─┤ X ├─┤ H ├─┤ X ├─\n", + " └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ \n", + "T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │\n" ] } ], @@ -112,40 +131,90 @@ "marked_states = [3]\n", "N = 2**n_search\n", "\n", - "# Build the oracle and Grover matrices\n", - "oracle = build_oracle_matrix(n_search, marked_states)\n", - "print(\"Oracle matrix:\")\n", - "print(oracle)\n", - "\n", - "grover = build_grover_matrix(n_search, marked_states)\n", - "print(\"\\nGrover operator G:\")\n", - "print(np.round(grover, 4))\n", + "# Build the oracle circuit using primitives from grovers_search\n", + "oracle_circ = build_oracle_circuit(n_search, marked_states)\n", + "print(\"Oracle circuit (marks state |11>):\")\n", + "print(oracle_circ)\n", "\n", - "# Verify eigenvalues\n", - "eigenvalues = np.linalg.eigvals(grover)\n", - "print(f\"\\nEigenvalues of G: {np.round(eigenvalues, 4)}\")" + "# Build the full Grover operator circuit: G = Diffusion . Oracle\n", + "grover_circ = build_grover_circuit(n_search, marked_states)\n", + "print(\"\\nGrover operator circuit (G = D . O):\")\n", + "print(grover_circ)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "c7e1a2b3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Grover circuit unitary shape: (8, 8)\n", + "(Includes 1 ancilla qubit(s) from MCZ decomposition)\n", + "\n", + "Non-trivial eigenvalues of G: [-0.5+0.866j -0.5-0.866j]\n", + "\n", + "Grover angle theta = 1.0472 rad\n", + "Ideal eigenvalues in solution subspace: e^(+i*theta) = 0.5000+0.8660j, e^(-i*theta) = 0.5000-0.8660j\n", + "Circuit eigenvalues (with -1 global phase): [-0.5+0.866j -0.5-0.866j]\n" + ] + } + ], + "source": [ + "# Extract the Grover operator unitary from the circuit\n", + "grover_unitary = grover_circ.to_unitary()\n", + "print(f\"Grover circuit unitary shape: {grover_unitary.shape}\")\n", + "print(f\"(Includes {grover_circ.qubit_count - n_search} ancilla qubit(s) from MCZ decomposition)\")\n", + "\n", + "# Eigenvalue analysis of the full circuit unitary\n", + "eigenvalues = np.linalg.eigvals(grover_unitary)\n", + "# Filter out trivial eigenvalues (1.0) to see the interesting ones\n", + "nontrivial = [ev for ev in eigenvalues if abs(ev - 1.0) > 0.01]\n", + "print(f\"\\nNon-trivial eigenvalues of G: {np.round(nontrivial, 4)}\")\n", + "\n", + "# In the 2D subspace spanned by |alpha> (unmarked) and |beta> (marked),\n", + "# the ideal Grover operator has eigenvalues e^{+/- i*theta}.\n", + "# However, the MCZ ancilla decomposition introduces a global phase of -1,\n", + "# so the circuit eigenvalues are -e^{+/- i*theta} = e^{+/- i*(theta + pi)}.\n", + "# This phase shift is corrected in get_quantum_counting_results.\n", + "theta = 2 * np.arcsin(np.sqrt(len(marked_states) / N))\n", + "print(f\"\\nGrover angle theta = {theta:.4f} rad\")\n", + "print(f\"Ideal eigenvalues in solution subspace: \"\n", + " f\"e^(+i*theta) = {np.exp(1j * theta):.4f}, \"\n", + " f\"e^(-i*theta) = {np.exp(-1j * theta):.4f}\")\n", + "print(f\"Circuit eigenvalues (with -1 global phase): {np.round(nontrivial, 4)}\")" ] }, { "cell_type": "markdown", - "id": "fee13411-62cb-41a0-91b6-32f2060b65f6", + "id": "fee13411", "metadata": {}, "source": [ - "## Build and Print the Quantum Counting Circuit" + "## Build the Quantum Counting Circuit\n", + "\n", + "The quantum counting circuit consists of four key components:\n", + "\n", + "1. **Initial state preparation**: Apply Hadamard gates to all counting qubits (QPE initialization) and all search qubits (prepare uniform superposition $|s\\rangle$)\n", + "2. **Controlled Grover operators**: Apply controlled-$G^{2^k}$ for each counting qubit $k$ (QPE phase kickback)\n", + "3. **Inverse QFT**: Applied to the counting qubits to extract the phase estimate\n", + "4. **Measurement**: Probability distribution over the counting (QPE) register only" ] }, { "cell_type": "code", - "execution_count": null, - "id": "d4537c2f-52dc-4126-9a91-26fdf5d0633b", + "execution_count": 4, + "id": "d4537c2f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Counting qubits: [0, 1, 2, 3]\n", - "Search qubits: [4, 5]\n", + "Counting qubits (QPE register): [0, 1, 2, 3]\n", + "Search qubits (data register): [4, 5]\n", "Search space size: N = 4\n", "Marked states: [3] (M = 1)\n", "\n", @@ -162,13 +231,16 @@ " └───┘ └─┬─┘ │ │ │ └──────┬───────┘ └───┘ │ │ └──────┬──────┘ \n", " ┌───┐ ┌───┐ │ │ │ │ ┌───┐ │ │ │ ┌──────┴──────┐ \n", "q3 : ─┤ H ├─┤ U ├───┼─────┼─────┼───────────────x─────┤ H ├────────●──────────────────────●─────────────────────────────────●───────────────────────────────────────────────────────┤ Probability ├─\n", - " └───┘ └─┬─┘ │ │ │ └───┘ └──────┬──────┘ \n", - " ┌───┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌──────┴──────┐ \n", - "q4 : ─┤ H ├─┤ U ├─┤ U ├─┤ U ├─┤ U ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ Probability ├─\n", - " └───┘ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ └──────┬──────┘ \n", - " ┌───┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌──────┴──────┐ \n", - "q5 : ─┤ H ├─┤ U ├─┤ U ├─┤ U ├─┤ U ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ Probability ├─\n", - " └───┘ └───┘ └───┘ └───┘ └───┘ └─────────────┘ \n", + " └───┘ └─┬─┘ │ │ │ └───┘ └─────────────┘ \n", + " ┌───┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ \n", + "q4 : ─┤ H ├─┤ U ├─┤ U ├─┤ U ├─┤ U ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n", + " └───┘ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ \n", + " ┌───┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ \n", + "q5 : ─┤ H ├─┤ U ├─┤ U ├─┤ U ├─┤ U ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n", + " └───┘ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ \n", + " ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ \n", + "q6 : ───────┤ U ├─┤ U ├─┤ U ├─┤ U ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n", + " └───┘ └───┘ └───┘ └───┘ \n", "T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ 12 │ Result Types │\n" ] } @@ -179,14 +251,14 @@ "counting_qubits = list(range(n_counting))\n", "search_qubits = list(range(n_counting, n_counting + n_search))\n", "\n", - "print(f\"Counting qubits: {counting_qubits}\")\n", - "print(f\"Search qubits: {search_qubits}\")\n", + "print(f\"Counting qubits (QPE register): {counting_qubits}\")\n", + "print(f\"Search qubits (data register): {search_qubits}\")\n", "print(f\"Search space size: N = {N}\")\n", "print(f\"Marked states: {marked_states} (M = {len(marked_states)})\")\n", "\n", "# Build the circuit\n", "circ = Circuit()\n", - "circ = quantum_counting_circuit(circ, counting_qubits, search_qubits, grover)\n", + "circ = quantum_counting_circuit(circ, counting_qubits, search_qubits, marked_states)\n", "\n", "print(\"\\nQuantum Counting Circuit:\")\n", "print(circ)" @@ -194,7 +266,7 @@ }, { "cell_type": "markdown", - "id": "3bc6f5fe-3771-47ce-a6eb-5d8b2d93442a", + "id": "3bc6f5fe", "metadata": {}, "source": [ "## Run on a Local Simulator" @@ -202,58 +274,56 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "8a31859a-8bc7-4901-a787-2dafc3c12fc8", + "execution_count": 5, + "id": "8a31859a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Quantum Counting Running...\n", - "Quantum Counting Run Complete\n", + "Search space size N = 4\n", + "\n", + "Counting register distribution (top outcomes):\n", + " |1011>: 369 counts -> phase = 0.1875, M ~ 1.2346\n", + " |0101>: 345 counts -> phase = 0.1875, M ~ 1.2346\n", + " |1010>: 77 counts -> phase = 0.1250, M ~ 0.5858\n", + " |0110>: 76 counts -> phase = 0.1250, M ~ 0.5858\n", + " |1100>: 28 counts -> phase = 0.2500, M ~ 2.0000\n", + " |0111>: 22 counts -> phase = 0.0625, M ~ 0.1522\n", + " ... (10 more outcomes)\n", "\n", - "Quantum Counting Results:\n", - "Measurement counts: Counter({'110111': 176, '001111': 152, '001101': 63, '001110': 62, '111011': 60, '001100': 59, '110110': 58, '110100': 58, '001011': 53, '110101': 48, '111111': 18, '001001': 16, '000111': 15, '111000': 15, '111001': 13, '110011': 13, '111010': 13, '001000': 10, '001010': 10, '010000': 8, '111101': 5, '110001': 5, '000011': 5, '110010': 5, '010001': 5, '010111': 4, '101110': 4, '011111': 4, '010011': 4, '100110': 3, '010110': 3, '011000': 3, '000110': 3, '011110': 3, '101111': 2, '011010': 2, '000000': 2, '101000': 2, '110000': 2, '010010': 2, '100010': 1, '101010': 1, '101001': 1, '010101': 1, '101011': 1, '000001': 1, '100011': 1, '011001': 1, '000101': 1, '010100': 1, '100100': 1, '011101': 1})\n", - "Counting register results: {'0011': 336, '1101': 340, '0010': 89, '1110': 101, '1111': 23, '0001': 19, '1001': 4, '1000': 2, '1100': 25, '1011': 6, '1010': 5, '0100': 19, '0101': 9, '0000': 8, '0110': 6, '0111': 8}\n", - "Phase estimates: [0.1875, 0.8125, 0.125, 0.875, 0.9375, 0.0625, 0.5625, 0.5, 0.75, 0.6875, 0.625, 0.25, 0.3125, 0.0, 0.375, 0.4375]\n", - "Estimated item counts: [np.float64(1.2346331352698203), np.float64(1.2346331352698203), np.float64(0.585786437626905), np.float64(0.5857864376269053), np.float64(0.15224093497742702), np.float64(0.15224093497742647), np.float64(3.8477590650225735), np.float64(4.0), np.float64(2.0000000000000004), np.float64(2.765366864730181), np.float64(3.414213562373095), np.float64(1.9999999999999996), np.float64(2.7653668647301797), np.float64(0.0), np.float64(3.414213562373095), np.float64(3.8477590650225735)]\n", "Best estimate of M: 1.2346331352698203\n", - "Search space size N: 4\n", "\n", "--- Summary ---\n", "Actual M = 1\n", - "Estimated M ≈ 1.2346\n", + "Estimated M = 1.2346\n", "Absolute error: 0.2346\n" ] } ], "source": [ - "# Run on local simulator\n", "device = LocalSimulator()\n", - "print(\"Quantum Counting Running...\")\n", - "task = run_quantum_counting(circ, device, shots=1000)\n", - "print(\"Quantum Counting Run Complete\")\n", + "task = device.run(circ, shots=1000)\n", "\n", - "# Get and display results\n", - "print(\"\\nQuantum Counting Results:\")\n", + "# Process results - uses only the counting register\n", "results = get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True)\n", "\n", "print(f\"\\n--- Summary ---\")\n", "print(f\"Actual M = {len(marked_states)}\")\n", - "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")\n", + "print(f\"Estimated M = {results['best_estimate']:.4f}\")\n", "print(f\"Absolute error: {abs(len(marked_states) - results['best_estimate']):.4f}\")" ] }, { "cell_type": "code", - "execution_count": null, - "id": "2ef4d059-766f-4045-b637-2b6a87ce64ae", + "execution_count": 6, + "id": "2ef4d059", "metadata": {}, "outputs": [ { "data": { - "image/png": "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XBUqVNDzzz+vb775Ri+//LJq166t3r17ZzqtZcuW6fDhwxo2bFiWjsYeOHBAzZo108mTJzV06FCVKFFCH374oa699lrNmDFD//nPf7KV05EjR9SxY0f16NFDN954o2bMmKHhw4crOjpanTp1Us2aNTV69Gg99dRTGjhwoKffmzVrdt7pTps2TceOHdNdd90ll8ull156ST169NDOnTs9R8e//vpr3XTTTYqOjtaYMWN05MgR9evXL8MjthfDXRiHhoZ6hj333HN68skndeONN6p///46dOiQ3nrrLbVq1Uq//vqrQkNDlZSUpA4dOigxMdHT13/99ZfmzJmjo0ePKiQk5JLiGjt2rOe668cff1ySFB4eLunsD1BjxoxR//791bhxYyUkJGj16tX65ZdfdM0112Q6zTVr1igpKUlXXXVVpm0ef/xxTZky5YJHu8+cOeP5ceFCwsLClCfP/46RHDt2TMOHD9djjz2miIiILE0jKypVqqSYmBh98skn6tSpkyTp22+/VXx8vG6++eYM8zly5IhSUlIuOO3ChQurcOHC2YorJCREVapU0Y8//qj7778/W9MAAL8zAEDAOXr0qEmy7t27n7fdtddea5IsISHBzMz69OljFStWTNfu6aeftnM3+SdPnkzXrkOHDla5cmWvYRUrVjRJtnTpUs+wgwcPWlBQkD344IOeYZ999plJsu+//z7ddCXZ008/nW54xYoVrU+fPp7XkyZNMknWoUMHS01N9QyPiYkxl8tld999t2dYcnKylStXzlq3bp1uumm98cYbJsm++OKL87ZzGzZsmEmyH374wTPs2LFjFhkZaZUqVbKUlBSvWHft2uX1/u+//z7d59C6dWuTZFOmTPEMS0xMtIiICOvZs6dn2KpVq0ySTZo0KV1c5/btrl27TJKVKFHCDh8+7Bn+5ZdfmiSbPXu2Z1h0dLSVK1fOjh075hm2ePFik5Th8nKu1q1bW40aNezQoUN26NAh27Jliz388MMmybp06eJpt3v3bsubN68999xzXu9fv3695cuXzzP8119/NUn22WefZTpPd34ZfRbnLk8Z9UWtWrUyXDbq1q3rFXNWvffeeybJ1q9fn25cxYoVPdO84447rGDBgrZv3z4z+9/ykDZX97Cs/J27fD300EMWGRlpp0+fTjfv7HB/dqtWrbK3337bihUr5tk23HDDDXb11VdnOh/3tuFCfxmt+25FihTx2gZkpH379lazZs1s5wgA/saRbgAIQMeOHZMkFStW7Lzt3OOPHTt2wbbnKlSokOf/8fHxOnPmjFq3bq25c+cqPj7e62hjVFSU1xH3UqVKqXr16tq5c+dFzTOr+vXr53X6aZMmTbRixQr169fPMyxv3rxq2LCh1qxZc95pJSQkSLrwZ+n2zTffqHHjxmrRooVnWNGiRTVw4ECNGDFCmzZtUu3atS8mHc800l4TXaBAATVu3PiSP8ObbrpJxYsX97x295N7uvv27dP69ev12GOPeV0/27p1a0VHR3s+nwvZsmVLusscrr32Wr3//vue1zNnzlRqaqpuvPFGr2uAIyIidOWVV+r777/XY4895lm25s6dq86dO2f7KGh2hIaGauPGjdq2bZuuvPLKLL/vn3/+kSSvzzojTzzxhKZOnaoXXnhBb7zxRoZt6tate8HT2d3SHs3+/fff9cYbb+iTTz7J0Rubud14440aNmyY5syZo44dO2rOnDnnPWL/8ccf69SpUxec7qVei128eHH9+uuvlzQNAPAnim4ACEBpi+nzOXbsmFwul0qWLHnR8/jxxx/19NNPa8WKFTp58qTXuHOL7goVKqR7f/HixXXkyJGLnm9WnDs/dyzly5dPN/xCMQQHB0u68Gfp9scff2T4bGD3qfJ//PFHtorucuXKpbuOtXjx4lq3bt1FTyutcz8rd1Ho/lz++OMPSVLVqlXTvbdq1ar65ZdfsjSfSpUqaeLEiUpNTdWOHTv03HPP6dChQ153z962bZvMLNNi1n26e2RkpB544AG99tpr+vjjj9WyZUtde+216tWr1yWfWn4ho0ePVvfu3VWtWjXVrl1bHTt21O233646depk6f12gXsIVK5cWbfffrveffddPfrooxm2KV68eKbXhp/Pfffdp2bNmqlnz54X/d6sKFWqlGJjYzVt2jSdPHlSKSkpuv766zNt37x5c5/EcS4zy/I14AAQiCi6ASAAhYSEqGzZshcsyNatW6dy5cqpQIECkpTpF9Nzr7vcsWOH2rVrpxo1aui1115T+fLlVaBAAX3zzTd6/fXX0z17ObNroS9UgFxIZteDZja/jIZfKIYaNWpIktavX6/rrrvu4gI8j6x+1m6++gx9Nd1zFSlSxKtQbN68ua666io99thjnqOhqampcrlc+vbbbzOMK+2R9ldffVV9+/bVl19+qXnz5mno0KEaM2aMVq5cmeEPFG5ZuYb4fFq1aqUdO3Z45vvee+/p9ddf14QJE9S/f/9M31eiRAlJZ3/MKFeu3Hnn4b4j/osvvpjhMpeUlKTDhw9nKd5SpUopb968WrRokb777jvNnDnT6+Z9ycnJOnXqlHbv3q2wsDDPj0zZdeutt2rAgAGKi4tTp06dvK7XP9ehQ4ey1B9Fixa94F3Kz+fIkSPZ+mERAAIFdy8HgADVrVs37dq1S8uWLctw/A8//KDdu3d77hounT2CdvTo0XRt3Uc73WbPnq3ExER99dVXuuuuu9S5c2fFxsZ6nXJ+sc53JCqjuJKSkrR///5szy+rWrRooeLFi+uTTz7JUoFQsWLFDJ+HvWXLFs946X9HlM/N69zP+mL44mieO97t27enG5fRsKyqU6eOevXqpf/7v//Tnj17JElVqlSRmSkyMlKxsbHp/po2beo1jejoaD3xxBNaunSpfvjhB/3111+aMGGCpEv/fM/3WYaFhemOO+7QJ598or1796pOnTrnvRu69L8fb3bt2nXBeVepUsXz2WS0jC9fvlxlypTJ0p/7ru/uz7hHjx6KjIz0/P31119atGiRIiMj9cEHH1wwtgv5z3/+ozx58mjlypUXvGt5o0aNspTDpT5ne9euXdm+KSMABAKOdANAgHrooYc0depU3XXXXVq6dKnnSJskHT58WHfffbeCg4M1ePBgz/AqVaooPj5e69at85wuu3//fn3xxRde03YfhUx7NDQ+Pl6TJk3KdrxFihSRlL5Icse1dOlSr2HvvvvuJR+1zIrChQtr+PDhevTRRzV8+HC9/PLL6Qqyjz76SNWqVVPjxo3VuXNnjR07VitWrFBMTIwk6cSJE3r33XdVqVIlRUVFeXKSpKVLl6pevXqSzh6Ffffdd7Md6/k+w+wqW7asateurSlTpmjEiBGeI45LlizR+vXrPUV5djzyyCOaMmWKXnvtNY0dO1Y9evTQiBEjNGrUKH300Uden7OZ6fDhwypRooQSEhJUuHBhr+dBR0dHK0+ePEpMTJR09rKAkiVLaunSpRo2bJinXVbv1F+kSJEMP8d//vnHa10qWrSoqlatmu6RZudq0KCBChQooNWrV+vaa6+94Pzd13anfSycW3au6W7btm269ViSBg4cqIoVK+rxxx9XdHR0lqZ5PkWLFtX48eO1e/dudevW7bxtL8c13fHx8dqxY4fuueeebE8DAPyNohsAAlTVqlU1ZcoU3XLLLYqOjla/fv0UGRmp3bt36/3339eRI0c0ffp0RUZGet5z8803a/jw4frPf/6joUOH6uTJkxo/fryqVavmde1u+/btVaBAAXXr1k133XWXjh8/rokTJ6p06dLZPvpcr1495c2bVy+++KLi4+MVFBTkeQ54//79dffdd6tnz5665ppr9Ntvv2nu3LmX7ZTRhx9+WBs3btSrr76q77//Xtdff70iIiIUFxenWbNm6eeff9by5cslSY8++qjnsUlDhw5VWFiYPvzwQ+3atUuff/655/FNtWrVUtOmTTVixAgdPnxYYWFhmj59upKTk7MdZ5UqVRQaGqoJEyaoWLFiKlKkiJo0aeLVx9nx/PPPq3v37mrevLnuuOMOHTlyRG+//bZq166t48ePZ3u6UVFR6ty5s9577z09+eSTqlKlip599lmNGDFCu3fv1nXXXadixYpp165d+uKLLzRw4EA99NBDWrRokQYPHqwbbrhB1apVU3JysqZOnaq8efN6Xa/cv39/vfDCC+rfv78aNmyopUuX6vfff89SbA0aNND48eP17LPPqmrVqipdurTatm2rqKgotWnTRg0aNFBYWJhWr16tGTNmeP14lZGCBQuqffv2WrBggUaPHn3B+buPdn/44YfpxmXnmu4KFSpkeG+FYcOGKTw8PN1p7H379vUstxf7LPY+ffpkqV12r+mePXu2fvvtN0lnH5+2bt06Pfvss5LO3pwv7fX1CxYskJmpe/fu2ZoXAAQEP901HQCQRevXr7dbb73VIiIiLE+ePCbJChYsaBs3bsyw/bx586x27dpWoEABq169un300UcZPjLsq6++sjp16ljBggWtUqVK9uKLL9oHH3yQ7jFFmT2SqHXr1ukeyTRx4kSrXLmy5c2b1+uxWSkpKTZ8+HArWbKkFS5c2Dp06GDbt2/P9JFhq1at8pquO/5Dhw55De/Tp48VKVLkAp/g/8yYMcPat29vYWFhli9fPitTpozddNNNtnjxYq92O3bssOuvv95CQ0OtYMGC1rhxY5szZ0666e3YscNiY2MtKCjIwsPD7bHHHrP58+dn+MiwWrVqpXt/Ro94+/LLLy0qKsry5cvn9ciszB4Z9vLLL6ebrjJ4TNP06dOtRo0aFhQUZLVr17avvvrKevbsaTVq1Dj/h3ae+M3+9+ixtPP7/PPPrUWLFlakSBErUqSI1ahRwwYNGmRbt241M7OdO3fanXfeaVWqVLGCBQtaWFiYXX311bZgwQKvaZ88edL69etnISEhVqxYMbvxxhvt4MGDWXpkWFxcnHXp0sWKFStmkjzL6rPPPmuNGze20NBQK1SokNWoUcOee+45S0pKuuDnMHPmTHO5XLZnzx6v4ZmtI9u2bfOsC+d7PNqlyGzePXv2tEKFCtmRI0fO+/7M1rmszic7+vTpk+njxc59RNxNN91kLVq0yJH5AoC/uMxy+E4rAACfmjJlivr27atevXppypQp/g4HuVi9evVUqlSpLJ/q/G+XkpKiqKgo3XjjjXrmmWf8Hc55hYeHq3fv3nr55Zf9HUq2xcXFKTIyUtOnT+dIN4BcjRupAUAu07t3b40ZM0ZTp07VY4895u9wkAucOXMm3Wnvixcv1m+//aY2bdr4J6hcKG/evBo9erTGjRt3Safl+9rGjRt16tQpDR8+3N+hXJKxY8cqOjqaghtArseRbgAAHG737t2KjY1Vr169VLZsWW3ZskUTJkxQSEiINmzY4HVjMQAAkLO4kRoAAA5XvHhxNWjQQO+9954OHTqkIkWKqEuXLnrhhRcouAEA8DGOdAMAAAAA4CNc0w0AAAAAgI9QdAMAAAAA4CNc0y0pNTVV+/btU7FixeRyufwdDgAAAAAgwJmZjh07prJlyypPnsyPZ1N0S9q3b5/Kly/v7zAAAAAAALnM3r17Va5cuUzHU3RLKlasmKSzH1ZwcLCfowEAAAAABLqEhASVL1/eU09mhqJb8pxSHhwcTNENAAAAAMiyC12i7NcbqY0fP1516tTxFLsxMTH69ttvPePbtGkjl8vl9Xf33Xd7TWPPnj3q0qWLChcurNKlS+vhhx9WcnLy5U4FAAAAAIB0/Hqku1y5cnrhhRd05ZVXysz04Ycfqnv37vr1119Vq1YtSdKAAQM0evRoz3sKFy7s+X9KSoq6dOmiiIgILV++XPv371fv3r2VP39+Pf/885c9HwAAAAAA0nKZmfk7iLTCwsL08ssvq1+/fmrTpo3q1aunsWPHZtj222+/VdeuXbVv3z6Fh4dLkiZMmKDhw4fr0KFDKlCgQJbmmZCQoJCQEMXHx3N6OQAAAADggrJaRwbMc7pTUlI0ffp0nThxQjExMZ7hH3/8sUqWLKnatWtrxIgROnnypGfcihUrFB0d7Sm4JalDhw5KSEjQxo0bL2v8AAAAAACcy+83Ulu/fr1iYmJ0+vRpFS1aVF988YWioqIkSbfeeqsqVqyosmXLat26dRo+fLi2bt2qmTNnSpLi4uK8Cm5JntdxcXGZzjMxMVGJiYme1wkJCTmdFgAAAAAA/i+6q1evrrVr1yo+Pl4zZsxQnz59tGTJEkVFRWngwIGedtHR0SpTpozatWunHTt2qEqVKtme55gxYzRq1KicCB8AAAAAgEz5/fTyAgUKqGrVqmrQoIHGjBmjunXr6o033siwbZMmTSRJ27dvlyRFRETowIEDXm3cryMiIjKd54gRIxQfH+/527t3b06kAgAAAACAF78X3edKTU31OvU7rbVr10qSypQpI0mKiYnR+vXrdfDgQU+b+fPnKzg42HOKekaCgoI8jynj2dwAAAAAAF/x6+nlI0aMUKdOnVShQgUdO3ZM06ZN0+LFizV37lzt2LFD06ZNU+fOnVWiRAmtW7dO999/v1q1aqU6depIktq3b6+oqCjdfvvteumllxQXF6cnnnhCgwYNUlBQkD9TAwAAAADAv0X3wYMH1bt3b+3fv18hISGqU6eO5s6dq2uuuUZ79+7VggULNHbsWJ04cULly5dXz5499cQTT3jenzdvXs2ZM0f33HOPYmJiVKRIEfXp08frud4AAAAAAPhLwD2n2x94TjcAAAAA4GLkuud0AwAAAADgNBTdAAAAAAD4CEU3AAAAAAA+QtENAAAAAICP+PXu5bg4g99b5u8QsuTt/i38HQIAAAAABASOdAMAAAAA4CMU3QAAAAAA+AhFNwAAAAAAPsI13fArrlMHAAAA4GQc6QYAAAAAwEcougEAAAAA8BGKbgAAAAAAfISiGwAAAAAAH6HoBgAAAADARyi6AQAAAADwEYpuAAAAAAB8hKIbAAAAAAAfoegGAAAAAMBHKLoBAAAAAPARim4AAAAAAHyEohsAAAAAAB+h6AYAAAAAwEcougEAAAAA8BGKbgAAAAAAfISiGwAAAAAAH6HoBgAAAADARyi6AQAAAADwEYpuAAAAAAB8hKIbAAAAAAAfoegGAAAAAMBHKLoBAAAAAPARim4AAAAAAHyEohsAAAAAAB+h6AYAAAAAwEcougEAAAAA8BGKbgAAAAAAfISiGwAAAAAAH6HoBgAAAADARyi6AQAAAADwEYpuAAAAAAB8hKIbAAAAAAAf8WvRPX78eNWpU0fBwcEKDg5WTEyMvv32W8/406dPa9CgQSpRooSKFi2qnj176sCBA17T2LNnj7p06aLChQurdOnSevjhh5WcnHy5UwEAAAAAIB2/Ft3lypXTCy+8oDVr1mj16tVq27atunfvro0bN0qS7r//fs2ePVufffaZlixZon379qlHjx6e96ekpKhLly5KSkrS8uXL9eGHH2ry5Ml66qmn/JUSAAAAAAAe+fw5827dunm9fu655zR+/HitXLlS5cqV0/vvv69p06apbdu2kqRJkyapZs2aWrlypZo2bap58+Zp06ZNWrBggcLDw1WvXj0988wzGj58uEaOHKkCBQr4Iy0AAAAAACQF0DXdKSkpmj59uk6cOKGYmBitWbNGZ86cUWxsrKdNjRo1VKFCBa1YsUKStGLFCkVHRys8PNzTpkOHDkpISPAcLQcAAAAAwF/8eqRbktavX6+YmBidPn1aRYsW1RdffKGoqCitXbtWBQoUUGhoqFf78PBwxcXFSZLi4uK8Cm73ePe4zCQmJioxMdHzOiEhIYeyAQAAAADgf/x+pLt69epau3atfvrpJ91zzz3q06ePNm3a5NN5jhkzRiEhIZ6/8uXL+3R+AAAAAIB/J78X3QUKFFDVqlXVoEEDjRkzRnXr1tUbb7yhiIgIJSUl6ejRo17tDxw4oIiICElSREREuruZu1+722RkxIgRio+P9/zt3bs3Z5MCAAAAAEABUHSfKzU1VYmJiWrQoIHy58+vhQsXesZt3bpVe/bsUUxMjCQpJiZG69ev18GDBz1t5s+fr+DgYEVFRWU6j6CgIM9jytx/AAAAAADkNL9e0z1ixAh16tRJFSpU0LFjxzRt2jQtXrxYc+fOVUhIiPr166cHHnhAYWFhCg4O1pAhQxQTE6OmTZtKktq3b6+oqCjdfvvteumllxQXF6cnnnhCgwYNUlBQkD9TAwAAAADAv0X3wYMH1bt3b+3fv18hISGqU6eO5s6dq2uuuUaS9PrrrytPnjzq2bOnEhMT1aFDB73zzjue9+fNm1dz5szRPffco5iYGBUpUkR9+vTR6NGj/ZUSAAAAAAAefi2633///fOOL1iwoMaNG6dx48Zl2qZixYr65ptvcjo0AAAAAAAuWcBd0w0AAAAAgFNQdAMAAAAA4CMU3QAAAAAA+AhFNwAAAAAAPkLRDQAAAACAj1B0AwAAAADgIxTdAAAAAAD4CEU3AAAAAAA+QtENAAAAAICPUHQDAAAAAOAjFN0AAAAAAPgIRTcAAAAAAD5C0Q0AAAAAgI9QdAMAAAAA4CMU3QAAAAAA+AhFNwAAAAAAPkLRDQAAAACAj1B0AwAAAADgIxTdAAAAAAD4CEU3AAAAAAA+QtENAAAAAICPUHQDAAAAAOAjFN0AAAAAAPgIRTcAAAAAAD5C0Q0AAAAAgI9QdAMAAAAA4CMU3QAAAAAA+AhFNwAAAAAAPkLRDQAAAACAj1B0AwAAAADgIxTdAAAAAAD4CEU3AAAAAAA+QtENAAAAAICPUHQDAAAAAOAjFN0AAAAAAPgIRTcAAAAAAD5C0Q0AAAAAgI9QdAMAAAAA4CMU3QAAAAAA+AhFNwAAAAAAPkLRDQAAAACAj/i16B4zZowaNWqkYsWKqXTp0rruuuu0detWrzZt2rSRy+Xy+rv77ru92uzZs0ddunRR4cKFVbp0aT388MNKTk6+nKkAAAAAAJBOPn/OfMmSJRo0aJAaNWqk5ORkPfbYY2rfvr02bdqkIkWKeNoNGDBAo0eP9rwuXLiw5/8pKSnq0qWLIiIitHz5cu3fv1+9e/dW/vz59fzzz1/WfAAAAAAASMuvRfd3333n9Xry5MkqXbq01qxZo1atWnmGFy5cWBERERlOY968edq0aZMWLFig8PBw1atXT88884yGDx+ukSNHqkCBAj7NAQAAAACAzATUNd3x8fGSpLCwMK/hH3/8sUqWLKnatWtrxIgROnnypGfcihUrFB0drfDwcM+wDh06KCEhQRs3brw8gQMAAAAAkAG/HulOKzU1VcOGDVPz5s1Vu3Ztz/Bbb71VFStWVNmyZbVu3ToNHz5cW7du1cyZMyVJcXFxXgW3JM/ruLi4DOeVmJioxMREz+uEhIScTgcAAAAAgMApugcNGqQNGzZo2bJlXsMHDhzo+X90dLTKlCmjdu3aaceOHapSpUq25jVmzBiNGjXqkuIFAAAAAOBCAuL08sGDB2vOnDn6/vvvVa5cufO2bdKkiSRp+/btkqSIiAgdOHDAq437dWbXgY8YMULx8fGev717915qCgAAAAAApOPXotvMNHjwYH3xxRdatGiRIiMjL/ietWvXSpLKlCkjSYqJidH69et18OBBT5v58+crODhYUVFRGU4jKChIwcHBXn8AAAAAAOQ0v55ePmjQIE2bNk1ffvmlihUr5rkGOyQkRIUKFdKOHTs0bdo0de7cWSVKlNC6det0//33q1WrVqpTp44kqX379oqKitLtt9+ul156SXFxcXriiSc0aNAgBQUF+TM9AAAAAMC/nF+PdI8fP17x8fFq06aNypQp4/n79NNPJUkFChTQggUL1L59e9WoUUMPPvigevbsqdmzZ3umkTdvXs2ZM0d58+ZVTEyMevXqpd69e3s91xsAAAAAAH/w65FuMzvv+PLly2vJkiUXnE7FihX1zTff5FRYAAAAAADkiIC4kRoAAAAAAE5E0Q0AAAAAgI9QdAMAAAAA4CMU3QAAAAAA+AhFNwAAAAAAPkLRDQAAAACAj1B0AwAAAADgIxTdAAAAAAD4CEU3AAAAAAA+QtENAAAAAICPUHQDAAAAAOAjFN0AAAAAAPgIRTcAAAAAAD5C0Q0AAAAAgI9QdAMAAAAA4CMU3QAAAAAA+AhFNwAAAAAAPkLRDQAAAACAj1B0AwAAAADgIxTdAAAAAAD4CEU3AAAAAAA+QtENAAAAAICPUHQDAAAAAOAjFN0AAAAAAPgIRTcAAAAAAD5C0Q0AAAAAgI9QdAMAAAAA4CMU3QAAAAAA+AhFNwAAAAAAPkLRDQAAAACAj1B0AwAAAADgIxTdAAAAAAD4CEU3AAAAAAA+QtENAAAAAICPUHQDAAAAAOAjFN0AAAAAAPgIRTcAAAAAAD5C0Q0AAAAAgI9QdAMAAAAA4CMU3QAAAAAA+AhFNwAAAAAAPuLXonvMmDFq1KiRihUrptKlS+u6667T1q1bvdqcPn1agwYNUokSJVS0aFH17NlTBw4c8GqzZ88edenSRYULF1bp0qX18MMPKzk5+XKmAgAAAABAOn4tupcsWaJBgwZp5cqVmj9/vs6cOaP27dvrxIkTnjb333+/Zs+erc8++0xLlizRvn371KNHD8/4lJQUdenSRUlJSVq+fLk+/PBDTZ48WU899ZQ/UgIAAAAAwCOfP2f+3Xffeb2ePHmySpcurTVr1qhVq1aKj4/X+++/r2nTpqlt27aSpEmTJqlmzZpauXKlmjZtqnnz5mnTpk1asGCBwsPDVa9ePT3zzDMaPny4Ro4cqQIFCvgjNQAAAAAAAuua7vj4eElSWFiYJGnNmjU6c+aMYmNjPW1q1KihChUqaMWKFZKkFStWKDo6WuHh4Z42HTp0UEJCgjZu3HgZowcAAAAAwJtfj3SnlZqaqmHDhql58+aqXbu2JCkuLk4FChRQaGioV9vw8HDFxcV52qQtuN3j3eMykpiYqMTERM/rhISEnEoDAAAAAACPbB3p/uWXX7R+/XrP6y+//FLXXXedHnvsMSUlJWUrkEGDBmnDhg2aPn16tt5/McaMGaOQkBDPX/ny5X0+TwAAAADAv0+2iu677rpLv//+uyRp586duvnmm1W4cGF99tlneuSRRy56eoMHD9acOXP0/fffq1y5cp7hERERSkpK0tGjR73aHzhwQBEREZ42597N3P3a3eZcI0aMUHx8vOdv7969Fx0zAAAAAAAXkq2i+/fff1e9evUkSZ999platWqladOmafLkyfr888+zPB0z0+DBg/XFF19o0aJFioyM9BrfoEED5c+fXwsXLvQM27p1q/bs2aOYmBhJUkxMjNavX6+DBw962syfP1/BwcGKiorKcL5BQUEKDg72+gMAAAAAIKdl65puM1NqaqokacGCBerataskqXz58vr777+zPJ1BgwZp2rRp+vLLL1WsWDHPNdghISEqVKiQQkJC1K9fPz3wwAMKCwtTcHCwhgwZopiYGDVt2lSS1L59e0VFRen222/XSy+9pLi4OD3xxBMaNGiQgoKCspMeAAAAAAA5IltFd8OGDfXss88qNjZWS5Ys0fjx4yVJu3btSndTs/Nxv69NmzZewydNmqS+fftKkl5//XXlyZNHPXv2VGJiojp06KB33nnH0zZv3ryaM2eO7rnnHsXExKhIkSLq06ePRo8enZ3UAAAAAADIMdkqul9//XX16tVLs2bN0uOPP66qVatKkmbMmKFmzZpleTpmdsE2BQsW1Lhx4zRu3LhM21SsWFHffPNNlucLAAAAAMDlkK2iu27dul53L3d7+eWXlS9fwDyFDAAAAAAAv8rWjdQqV66sf/75J93w06dPq1q1apccFAAAAAAATpCtonv37t1KSUlJNzwxMVF//vnnJQcFAAAAAIATXNS54F999ZXn/3PnzlVISIjndUpKihYuXJjusV8AAAAAAPxbXVTRfd1110mSXC6X+vTp4zUuf/78qlSpkl599dUcCw4AAAAAgNzsoopu97O5IyMjtWrVKpUsWdInQQEAAAAA4ATZutX4rl27cjoOAAAAAAAcJ9vP91q4cKEWLlyogwcPeo6Au33wwQeXHBgAAAAAALldtoruUaNGafTo0WrYsKHKlCkjl8uV03EBAAAAAJDrZavonjBhgiZPnqzbb789p+MBAAAAAMAxsvWc7qSkJDVr1iynYwEAAAAAwFGyVXT3799f06ZNy+lYAAAAAABwlGydXn769Gm9++67WrBggerUqaP8+fN7jX/ttddyJDgAAAAAAHKzbBXd69atU7169SRJGzZs8BrHTdUAAAAAADgrW0X3999/n9NxAAAAAADgONm6phsAAAAAAFxYto50X3311ec9jXzRokXZDggAAAAAAKfIVtHtvp7b7cyZM1q7dq02bNigPn365ERcAAAAAADketkqul9//fUMh48cOVLHjx+/pIAAAAAAAHCKHL2mu1evXvrggw9ycpIAAAAAAORaOVp0r1ixQgULFszJSQIAAAAAkGtl6/TyHj16eL02M+3fv1+rV6/Wk08+mSOBAQAAAACQ22Wr6A4JCfF6nSdPHlWvXl2jR49W+/btcyQwAAAAAAByu2wV3ZMmTcrpOAAAAAAAcJxsFd1ua9as0ebNmyVJtWrVUv369XMkKAAAAAAAnCBbRffBgwd18803a/HixQoNDZUkHT16VFdffbWmT5+uUqVK5WSMAAAAAADkStm6e/mQIUN07Ngxbdy4UYcPH9bhw4e1YcMGJSQkaOjQoTkdIwAAAAAAuVK2jnR/9913WrBggWrWrOkZFhUVpXHjxnEjNQAAAAAA/r9sHelOTU1V/vz50w3Pnz+/UlNTLzkoAAAAAACcIFtFd9u2bXXfffdp3759nmF//fWX7r//frVr1y7HggMAAAAAIDfLVtH99ttvKyEhQZUqVVKVKlVUpUoVRUZGKiEhQW+99VZOxwgAAAAAQK6UrWu6y5cvr19++UULFizQli1bJEk1a9ZUbGxsjgYHAAAAAEBudlFHuhctWqSoqCglJCTI5XLpmmuu0ZAhQzRkyBA1atRItWrV0g8//OCrWAEAAAAAyFUuqugeO3asBgwYoODg4HTjQkJCdNddd+m1117LseAAAAAAAMjNLqro/u2339SxY8dMx7dv315r1qy55KAAAAAAAHCCiyq6Dxw4kOGj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U7FixRQRESEpdy13HTp0cMxy57T1SHLe9jtPnjxq3769br/9dlWsWNGzzkjSkiVL1KFDB6WkpChPnjwBn48Tvzc4MSfJWfskN6fl5LRtneTMfdJF82/Nj0Cyd+9ez69M5/u1dubMmRYSEmLr1q0zs8D+Reqff/7x5HK+OD/55BMrVqyYbd68+YJt/enbb7+1UaNG2SOPPGKff/55pnHmpj768ccfbcaMGTZlyhTbu3dvpu0mTZpkRYoUse3bt1/G6C7eokWLbPz48fbKK6/Yzz//nOlnn1uWOTOzLVu22PHjx83s/NuGr7/+2kqWLGmrVq0ys8DOyX1E0ez8ceaW5c5p65GZ87bfa9asse+//96+/vprr+XvXOPHj7dixYrZH3/8cRmjyx4nfm9wWk5O3Cc5LSenbevMnLlPulQU3TAzs48++shq165tH330kSUmJppZ+pU5NTXVUlJS7P7777d7773XkpKSAvpUqqlTp1rLli1t+fLlmW6YUlNT7dSpUzZw4EB76KGHzCxwTw+bNGmSFSpUyG666SarXr261apVy9q0aeP58pacnJzr+ui9996z4OBga9KkieXPn98aNWpkTz/9tKe/3DklJCRYr1697MknnzSzwO2j999/34oWLWrt27e3sLAwq1u3rvXt29cTrzuf3LLMmZ3dNlxxxRX2zDPP2LFjx8ws8x39E088YX379rWEhISA/jIwZcoU6969u+eU0IzkpuXOaeuRmfO23xMnTrQSJUpYrVq1zOVyWZs2beyDDz7wjE9JSbHU1FQ7dOiQ9ejRw8aMGeMZHqic+L3BaTk5cZ/ktJyctq0zc+Y+KSdQdMPmzZtn5cqVs3Llylnjxo3t008/zXRnExcXZ+XKlbP333/fH6Fm2bfffmulS5e2ggUL2lVXXXXeX0J37dplZcuW9bpmJtDs37/fatasaePHjzczs9OnT9vs2bMtOjraatWq5TkKaZZ7+mjjxo12xRVX2LRp0+z06dN25MgRu++++6xBgwZ25513evXXhg0brGzZsjZ79mw/Rnx+O3futMjISJs8ebKZmR0/ftzeeOMNq1OnjrVr185rZ5Ibljkzs4ULF1pkZKTVrVvXmjVrZi+88EKmhffhw4etUqVK9uabb/oj1CybM2eOBQcHm8vlsvbt21tcXFymbXPDcue09cjMedvvVatWWenSpe3TTz+1AwcO2B9//GHXXnutNW3a1EaPHu2V208//WRly5a1hQsX+jHiC3Pi9wan5eTEfZLTcnLats7MmfuknBL4F5/Ap06dOqVly5apY8eO+vHHH1W6dGmNGTNGs2bNUlJSklwul8zMq/1zzz2nO++8049Rn198fLzmz5+vW265RTt27NCZM2d05513avXq1Z5c0uaUkJCghx9+WDfddJO/Qr6gU6dOKT4+XvXr15ckBQUFqVOnTpo6dary5s2rtm3benI6efJkwPeRJB04cEAul0utWrVSUFCQQkNDNWrUKN1222369ddf9dBDD3naHj58WP3791fXrl39GPH5HT16VKdOnVKTJk0kSUWKFNGAAQM0atQoxcXF6cYbb/T0UXx8fMAvcykpKVqzZo2aNWumL774QldddZVmzJihcePG6fjx43K5XJ5nbUpn16lx48ZpyJAhnteB5tChQ5o1a5buvPNO/fzzz/r99991yy236MCBAxm2zw3LndPWIyduv/fs2aOQkBB16NBBpUuXVoUKFfT++++rUaNGmjNnjt566y1P24MHD+r6669X27Zt/Rjx+Tnxe4MTc3LaPklyVk5O3NZJztsn5Sg/FPoIIKmpqbZ27Vr74YcfzOzsKR9dunSxevXq2aeffuq5rimtEydOeN4biJKSkmzevHm2ZMkSMzt7x8TatWtb7dq17eeff87w9JWTJ0+aWeDmlJiYaDVr1rQRI0akG7dkyRKLioqyZ5991qu9WeDmY2a2du1aq1y5sn377bdm9r9Yjx07ZiNHjrQGDRp4+tAs8HPat2+fVa1a1SZMmOA1PDEx0T788EOrW7euTZ061Wu4WeDmY3b2DIsff/zRzM7Gee+991rDhg3thRdesISEhHTt3etRoDp58qRNnTrVs73btm2bVaxY0a6++upMj3i7L98I1H5y2nqUlJRkc+fOddT2+9tvv7XIyEjbsGGDmZ3NyezsdZx9+vSx5s2be13PmJSUZGaBm48Tvzc4Maf9+/dblSpVHLdPckpOTtzWmTlvn5STKLrh+QLgXuDPnDnjtbM5c+aMxcfH29tvv+3PMLMkbQ5m/7s+JCkpybMxc9/k6ejRo/bpp5/6J9CLkJqaasnJyfbwww9by5YtvR7P5B5/++23W5cuXXLVRuuff/6xBg0a2PXXX2///POP17gTJ05Y5cqV7ZFHHvFTdBcvISHBevbsaR06dLD169d7jUtKSrJWrVpZ3759/RTdxclsOUpOTvYqvE+cOGHHjh3zulYr0J17A6vff//dU3gfOHDAzMyOHDliixYt8kd4F+3QoUN21VVXOWY9MvvflzAnbL/NzP78808LDw+3wYMHe4YlJyebmdnff/9tISEh9vLLL/srvIviXs/P/dcJ3xuclJPZ2fX/+uuvd8Q+yc1pOTltW2fmzH1STqHo/hdau3atff311/bDDz94ju6cW6wmJSVZly5drH79+jZx4kSLiYmxxo0bB+xNDjL6FdrNnVNiYqLVrl3boqOj7bvvvrOYmBjr1KlTQBYL8fHxnv+749u9e7c1bdrU2rdvb/PmzfNq//rrr1urVq0C+khj2j5yL0erV6+2oKAgu/fee9MdOb3zzjvtzjvvvKwxXoy065H7hlwbN2608PBw6969u23ZssWr/YgRI6x79+6eL9uBKO1ydy533GfOnLFBgwZZ48aN7cknn7SYmBirUqVKwOa1Z88e27Rpkx09etRTcLtvWuW2detWq1ixorVt29bWr19vTZs2tdtuuy0gtw1bt261H3/80bZv326HDx82M7OVK1dagQIF7J577sl165HZ/3Latm2b59mz7m1Ebtx+p13m3EdDZ86caXnz5vU6I8kde9euXQP+S6g7j4y41/3c9r3BaTmlzccd35YtWyw8PNyuu+66XLlPclpOTtvWmTlzn+QrFN3/MhMnTrSIiAiLjIy0ihUrWtWqVe3777/3apP2KHGHDh3M5XJZnTp1AvaUty+//NKee+65894QyR17cnKy5+6xtWrVCsicPv30U2vXrp3XY5fcO5AtW7bYVVddZbGxsfbWW29ZYmKi7d+/39q1a2e33367P8M+r4z6yJ3T7NmzLSgoyHr16mW//fabpaam2smTJ61x48Y2fPhwf4V8XhmtR/Pnzzezs8V4aGiodevWzb766itLTk62I0eOWMuWLe2ee+7xc+SZO3e5y4i7z1JTU61fv37mcrnsqquu8qxHgfZF9IMPPrCqVataRESEValSxQYMGGC///67mXnnYma2fft2q1SpkrlcLqtRo4Ynp0Dy3nvvWfny5a1s2bJWqVIla9u2rf3yyy9mZjZr1iwrUKBArlqPzNLn1K5dO88jmNIe/THLHdvvtMtc1apVrX///rZ161YzMxs7dqzl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Q4cO1SOPPKKwsDBFRERo5MiRnvGVKlWSJP3nP/+Ry+XyvD739HL3vF555RWVKVNGJUqU0KBBg3TmzBlPm/3796tLly4qVKiQIiMjNW3aNFWqVEljx4497+eRL18+RURE6IorrlBsbKxuuOEGzZ8/36vNe++9p5o1a6pgwYKqUaOG3nnnHa/xy5cvV7169VSwYEE1bNhQs2bNksvl0tq1ayWlP3r9xx9/qFu3bipevLiKFCmiWrVq6ZtvvtHu3bt19dVXS5KKFy8ul8ulvn37SpJSU1M1ZswYRUZGqlChQqpbt65mzJjhicE9j2+//VYNGjRQUFCQli1blmneffr00fTp03Xq1CnPsA8++EB9+vRJ13bv3r268cYbFRoaqrCwMHXv3l27d+/2jF+1apWuueYalSxZUiEhIWrdurV++eUXz3gz08iRI1WhQgUFBQWpbNmyGjp0qGd8Rmc7hIaGavLkyZLO/lDkcrn06aefqnXr1ipYsKA+/vjjC/aN+33//e9/1bJlSxUqVEiNGjXS77//rlWrVqlhw4YqWrSoOnXqpEOHDnnNPyvTnTlzpq6++moVLlxYdevW1YoVKzx9cccddyg+Pt5zVkHa5R4A4CcGAICP/fPPP+Zyuez5558/b7uUlBSrV6+etWjRwlavXm0rV660Bg0aWOvWrT1t+vTpY927d/d633333efVpnXr1hYcHGwjR46033//3T788ENzuVw2b948MzM7ePCgSbJJkybZ/v377eDBg2Zm9vTTT1vdunW95hUcHGx33323bd682WbPnm2FCxe2d99919MmNjbW6tWrZytXrrQ1a9ZY69atrVChQvb6669nmue589m1a5fVqlXLwsPDPcM++ugjK1OmjH3++ee2c+dO+/zzzy0sLMwmT55sZmbx8fEWFhZmvXr1so0bN9o333xj1apVM0n266+/mpnZ999/b5LsyJEjZmbWpUsXu+aaa2zdunW2Y8cOmz17ti1ZssSSk5Pt888/N0m2detW279/vx09etTMzJ599lmrUaOGfffdd7Zjxw6bNGmSBQUF2eLFi73mUadOHZs3b55t377d/vnnnwzzlmRffPGF1alTx6ZOnWpmZn/88YcFBQXZ77//bpLs+++/NzOzpKQkq1mzpt155522bt0627Rpk916661WvXp1S0xMNDOzhQsX2tSpU23z5s22adMm69evn4WHh1tCQoKZmX322WcWHBxs33zzjf3xxx/2008/efWdO560QkJCbNKkSZ5+kWSVKlXy9MO+ffsu2Dfu97k/t02bNlnTpk2tQYMG1qZNG1u2bJn98ssvVrVqVbv77ruz3OdppztnzhzbunWrXX/99VaxYkU7c+aMJSYm2tixYy04ONj2799v+/fvt2PHjmW6HAIALg+KbgCAz/30008myWbOnHnedvPmzbO8efPanj17PMM2btxokuznn382s6wX3S1atPBq06hRIxs+fLjndUYFV0ZFd8WKFS05Odkz7IYbbrCbbrrJzMw2b95skmzVqlWe8du2bTNJFyy68+TJY0WKFLGCBQuaJJNkr732mqdNlSpVbNq0aV7ve+aZZywmJsbMzMaPH28lSpSwU6dOecZPnDjxvEV3dHS0jRw5MsOYzm1rZnb69GkrXLiwLV++3Kttv3797JZbbvF636xZszLN1839mY8dO9auvvpqMzMbNWqU/ec//7EjR454Fd1Tp0616tWrW2pqquf9iYmJVqhQIZs7d26G009JSbFixYrZ7Nmzzczs1VdftWrVqllSUtJ540kro6J77NixXm0u1Dfu97333nue8Z988olJsoULF3qGjRkzxqpXr35J03WvH5s3bzYzs0mTJllISEiG+QIA/INrugEAPmdmWWq3efNmlS9fXuXLl/cMi4qKUmhoqDZv3qxGjRpleZ516tTxel2mTBkdPHgwy+93q1WrlvLmzes1nfXr10uStm7dqnz58umqq67yjK9ataqKFy9+welWr15dX331lU6fPq2PPvpIa9eu1ZAhQyRJJ06c0I4dO9SvXz8NGDDA857k5GTPTdG2bt2qOnXqqGDBgp7xjRs3Pu88hw4dqnvuuUfz5s1TbGysevbsme5zSmv79u06efKkrrnmGq/hSUlJql+/vtewhg0bXjBnt169eunRRx/Vzp07NXnyZL355pvp2vz222/avn27ihUr5jX89OnT2rFjhyTpwIEDeuKJJ7R48WIdPHhQKSkpOnnypPbs2SNJuuGGGzR27FhVrlxZHTt2VOfOndWtW7dMrzfPTNrcstI3bmk/2/DwcElSdHS01zD3Mpnd6ZYpU0aSdPDgQdWoUeOi8gIAXB4U3QAAn7vyyivlcrly5GZpefLkSVfEp73G2u3cm125XC6lpqZe9PxyajrnKlCggKpWrSpJeuGFF9SlSxeNGjVKzzzzjI4fPy5Jmjhxopo0aeL1vrQ/AFys/v37q0OHDvr66681b948jRkzRq+++qqn2D+XO46vv/5aV1xxhde4oKAgr9dFihTJchwlSpRQ165d1a9fP50+fVqdOnXSsWPH0s27QYMGnmuo0ypVqpSks9eH//PPP3rjjTdUsWJFBQUFKSYmRklJSZLO3rRt69atWrBggebPn697771XL7/8spYsWaL8+fPL5XJlaVlKm9vF9E3aZcflcmU4zL0sXep0c2KZBAD4BjdSAwD4XFhYmDp06KBx48bpxIkT6ca7b/RVs2ZN7d27V3v37vWM27Rpk44ePaqoqChJZwuu/fv3e73ffeOwi5E/f36lpKRc9PvSql69upKTk/Xrr796hm3fvl1Hjhy56Gk98cQTeuWVV7Rv3z6Fh4erbNmy2rlzp6pWrer1FxkZ6Zn3+vXrlZiY6JnGqlWrLjif8uXL6+6779bMmTP14IMPauLEiZLO/gggyesziYqKUlBQkPbs2ZMujrRnI2THnXfeqcWLF6t3794Z/pBw1VVXadu2bSpdunS6ebuP/P74448aOnSoOnfurFq1aikoKEh///2313QKFSqkbt266c0339TixYu1YsUKz5kK5y5L27Zt08mTJ88bd1b6JjtyaroFChS45OUaAJCzKLoBAJfFuHHjlJKSosaNG+vzzz/Xtm3btHnzZr355puKiYmRJMXGxio6Olq33XabfvnlF/3888/q3bu3Wrdu7TnFt23btlq9erWmTJmibdu26emnn9aGDRsuOp5KlSpp4cKFiouLy1aRLEk1atRQbGysBg4cqJ9//lm//vqrBg4cqEKFCnmOQGZVTEyM6tSpo+eff16SNGrUKI0ZM0Zvvvmmfv/9d61fv16TJk3Sa6+9Jkm69dZblZqaqoEDB2rz5s2aO3euXnnlFUnKdN7Dhg3T3LlztWvXLv3yyy/6/vvvVbNmTUlSxYoV5XK5NGfOHB06dEjHjx9XsWLF9NBDD+n+++/Xhx9+qB07duiXX37RW2+9pQ8//DBbn5lbx44ddejQIY0ePTrD8bfddptKliyp7t2764cfftCuXbu0ePFiDR06VH/++aeks2dQTJ06VZs3b9ZPP/2k2267TYUKFfJMY/LkyXr//fe1YcMG7dy5Ux999JEKFSqkihUrSjq7LL399tv69ddftXr1at19991ZehzYhfomu3JiupUqVdLx48e1cOFC/f333xf8EQEA4HsU3QCAy6Jy5cr65ZdfdPXVV+vBBx9U7dq1dc0112jhwoUaP368pLPF4pdffqnixYurVatWio2NVeXKlb2eXd2hQwc9+eSTeuSRR9SoUSMdO3ZMvXv3vuh4Xn31Vc2fP1/ly5dPd33yxZgyZYrCw8PVqlUr/ec//9GAAQNUrFgxr2uts+r+++/Xe++9p71796p///567733NGnSJEVHR6t169aaPHmy56hncHCwZs+erbVr16pevXp6/PHH9dRTT0lSpvNOSUnRoEGDVLNmTXXs2FHVqlXzPJLqiiuu0KhRo/Too48qPDxcgwcPliQ988wzevLJJzVmzBjP+77++utLOqorne3rkiVLeo6wn6tw4cJaunSpKlSooB49eqhmzZqe09GDg4MlSe+//76OHDmiq666SrfffruGDh2q0qVLe6YRGhqqiRMnqnnz5qpTp44WLFig2bNnq0SJEpLOLgPly5dXy5Ytdeutt+qhhx5S4cKFLxj7hfomu3Jius2aNdPdd9+tm266SaVKldJLL710STEBAC6dy7J6dxsAAHBBf/75p8qXL68FCxaoXbt2l3XeH3/8sec5zWmP+AIAAP/hRmoAAFyCRYsW6fjx44qOjtb+/fv1yCOPqFKlSmrVqpXP5z1lyhRVrlxZV1xxhX777TcNHz5cN954IwU3AAABhKIbAIBLcObMGT322GPauXOnihUrpmbNmunjjz/O0rXBlyouLk5PPfWU4uLiVKZMGd1www167rnnfD5fAACQdZxeDgAAAACAj3AjNQAAAAAAfISiGwAAAAAAH6HoBgAAAADARyi6AQAAAADwEYpuAAAAAAB8hKIbAAAAAAAfoegGAAAAAMBHKLoBAAAAAPARim4AAAAAAHzk/wEdEXhdX/8QugAAAABJRU5ErkJggg==", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAHqCAYAAAAZLi26AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAbupJREFUeJzt3Xd4FOX6//HP0hJaEkJJQAIEkBIIRWroQqSKeMAuAkqxUMSKWAELdjkq4ldUEBTxiIgHRKkCoqCAIh2pgkIABRJqQpL79we/3ZOFBELIspvh/bquvWBnZmfue59nJntPdZmZCQAAAAAA5Lp8/g4AAAAAAACnougGAAAAAMBHKLoBAAAAAPARim4AAAAAAHyEohsAAAAAAB+h6AYAAAAAwEcougEAAAAA8BGKbgAAAAAAfISiGwAAAAAAH6HoBgAgD+jTp48qVark7zAC0sSJE+VyubRz506fL+s///mPwsPDdfToUZ8v63L32GOPqUmTJv4OAwAuGkU3AAS49evXq2fPnrriiisUFBSkcuXKqWfPntqwYYO/Q/OyYcMGjRgx4pIUPjn15ZdfqlOnTipVqpQKFSqkcuXK6aabbtLChQv9HZokac+ePRoxYoRWr17t71C8tGnTRi6Xy/MqXLiw6tSpozFjxig9Pd3f4WXqnXfe0cSJE3N1nmlpaXrmmWc0ePBgFStWzDO8UqVKcrlcGjx48FmfWbRokVwul6ZNm5arsUhS//795XK5dO211+Z4Hu4dFi6XS0uXLj1rvJkpKirqopeT0bhx43TjjTeqQoUKcrlc6tOnT6bTDR06VL/99pv++9//5spyAcBfKLoBIIBNnz5dV111lRYsWKA777xT77zzjvr27auFCxfqqquu0ldffeXvED02bNigkSNHBmTRbWa688471b17d+3bt08PPvig3n33XQ0cOFDbt29Xu3bt9OOPP/o7TO3Zs0cjR47MtOgeP368Nm/efOmD+v/Kly+vyZMna/LkyRo9erSCg4P1wAMP6KmnnvJbTOfii6J75syZ2rx5swYMGJDp+PHjx2vPnj25usysrFy5UhMnTlRwcHCuzC84OFhTpkw5a/jixYv1559/KigoKFeWI0kvvfSSFi5cqFq1aqlAgQJZThcZGalu3brp1VdfzbVlA4A/ZL2lAwD41bZt23THHXeocuXKWrJkiUqXLu0Zd//996tly5bq2bOn1qxZo+joaD9GGvhee+01TZw4UUOHDtXrr78ul8vlGffEE09o8uTJ5/zxHwgKFizo1+WHhoaqZ8+envf33HOPatSoobfeekujRo1S/vz5/RjdpTFhwgQ1b95cV1xxxVnjatWqpc2bN+vFF1/Um2++6dM4zExDhgxRr169tGDBglyZZ+fOnfX555/rzTff9FoXpkyZogYNGujvv//OleVIpwt591HujGcMZOamm27SjTfeqO3bt6ty5cq5FgMAXEoc6QaAAPXKK6/o+PHjeu+997wKbkkqVaqU/u///k9Hjx7VK6+84hme1XW/I0aM8Co0pdMFRNu2bVWmTBkFBQUpJiZG48aNO+uzlSpV0rXXXqulS5eqcePGCg4OVuXKlTVp0iTPNBMnTtSNN94oSbr66qs9p6suWrRIkuRyuTRixIhM553x1FL3qa5Lly7VkCFDVLp0aYWFhenuu+9WSkqKDh8+rF69eqlEiRIqUaKEHn30UZnZOb/HEydOaPTo0apRo4ZeffXVs74HSbrjjjvUuHFjz/vt27frxhtvVHh4uIoUKaKmTZvq66+/9vpMVtcRu08nducunT49u3bt2tqwYYOuvvpqFSlSRFdccYVefvllr881atRIknTnnXd6vkP30doz23bnzp1yuVx69dVX9d5776lKlSoKCgpSo0aNtGLFirNy/PzzzxUTE6Pg4GDVrl1bX3755UVdJx4cHKxGjRrpyJEj2r9/v9e4jz/+WA0aNFDhwoUVHh6uW265Rbt37/aaZsuWLerRo4ciIyMVHBys8uXL65ZbblFiYqJXfpkdrc6qP7lVqlRJ69ev1+LFiz3fY5s2bSRJp06d0siRI3XllVcqODhYJUuWVIsWLTRv3rxz5nvy5El9++23io+Pz3KZvXr1uiRHuydPnqx169bp+eefz7V53nrrrfrnn3+8voeUlBRNmzZNt912W64tR5IqVqyY6XqYGff3HUhn9QDAhQrs3foAcBmbOXOmKlWqpJYtW2Y6vlWrVqpUqZJmzpypd95554LnP27cONWqVUvXXXedChQooJkzZ+q+++5Tenq6Bg4c6DXt1q1bdcMNN6hv377q3bu3PvzwQ/Xp00cNGjRQrVq11KpVKw0ZMkRvvvmmHn/8cdWsWVOSPP9eqMGDBysyMlIjR47U8uXL9d577yksLEw//vijKlSooBdeeEGzZ8/WK6+8otq1a6tXr15Zzmvp0qU6ePCghg4dmq2jsfv27VOzZs10/PhxDRkyRCVLltRHH32k6667TtOmTdO//vWvHOV06NAhdezYUd27d9dNN92kadOmadiwYYqNjVWnTp1Us2ZNjRo1Sk8//bQGDBjgafdmzZqdc75TpkzRkSNHdPfdd8vlcunll19W9+7dtX37ds/R8a+//lo333yzYmNjNXr0aB06dEh9+/bN9IjthXAXxmFhYZ5hzz//vJ566inddNNN6tevnw4cOKC33npLrVq10q+//qqwsDClpKSoQ4cOSk5O9rT1X3/9pVmzZunw4cMKDQ29qLjGjBnjue76iSeekCRFRERIOr0DavTo0erXr58aN26spKQkrVy5Ur/88ouuueaaLOe5atUqpaSk6KqrrspymieeeEKTJk0679HuU6dOeXYunE94eLjy5fvfMZIjR45o2LBhevzxxxUZGZmteWRHpUqVFBcXp08//VSdOnWSJH3zzTdKTEzULbfckmk+hw4dUlpa2nnnXaRIERUpUiRHcYWGhqpKlSr64Ycf9MADD+RoHgDgdwYACDiHDx82SdatW7dzTnfdddeZJEtKSjIzs969e1vFihXPmu6ZZ56xMzf5x48fP2u6Dh06WOXKlb2GVaxY0STZkiVLPMP2799vQUFB9tBDD3mGff755ybJvvvuu7PmK8meeeaZs4ZXrFjRevfu7Xk/YcIEk2QdOnSw9PR0z/C4uDhzuVx2zz33eIalpqZa+fLlrXXr1mfNN6N///vfJsm+/PLLc07nNnToUJNk33//vWfYkSNHLDo62ipVqmRpaWlese7YscPr8999991Z30Pr1q1Nkk2aNMkzLDk52SIjI61Hjx6eYStWrDBJNmHChLPiOrNtd+zYYZKsZMmSdvDgQc/wr776yiTZzJkzPcNiY2OtfPnyduTIEc+wRYsWmaRM+8uZWrdubTVq1LADBw7YgQMHbNOmTfbII4+YJOvSpYtnup07d1r+/Pnt+eef9/r82rVrrUCBAp7hv/76q0myzz//PMtluvPL7Ls4sz9l1ha1atXKtG/UrVvXK+bsev/9902SrV279qxxFStW9MzzzjvvtODgYNuzZ4+Z/a8/ZMzVPSw7rzP718MPP2zR0dF28uTJs5adE+7vbsWKFfb2229b8eLFPduGG2+80a6++uosl+PeNpzvldm671a0aFGvbUBm2rdvbzVr1sxxjgDgbxzpBoAAdOTIEUlS8eLFzzmde/yRI0fOO+2ZChcu7Pl/YmKiTp06pdatW2vOnDlKTEz0OtoYExPjdcS9dOnSql69urZv335By8yuvn37ep1+2qRJEy1btkx9+/b1DMufP78aNmyoVatWnXNeSUlJks7/XbrNnj1bjRs3VosWLTzDihUrpgEDBmj48OHasGGDateufSHpeOaR8ZroQoUKqXHjxhf9Hd58880qUaKE5727ndzz3bNnj9auXavHH3/c6/rZ1q1bKzY21vP9nM+mTZvOuszhuuuu0wcffOB5P336dKWnp+umm27yugY4MjJSV155pb777js9/vjjnr41Z84cde7cOcdHQXMiLCxM69ev15YtW3TllVdm+3P//POPJHl915l58sknNXnyZL344ov697//nek0devWPe/p7G4Zj2b//vvv+ve//61PP/00V29s5nbTTTdp6NChmjVrljp27KhZs2ad84j9J598ohMnTpx3vhd7LXaJEiX066+/XtQ8AMCfKLoBIABlLKbP5ciRI3K5XCpVqtQFL+OHH37QM888o2XLlun48eNe484suitUqHDW50uUKKFDhw5d8HKz48zluWOJioo6a/j5YggJCZF0/u/S7Y8//sj02cDuU+X/+OOPHBXd5cuXP+s61hIlSmjNmjUXPK+Mzvyu3EWh+3v5448/JElVq1Y967NVq1bVL7/8kq3lVKpUSePHj1d6erq2bdum559/XgcOHPC6e/aWLVtkZlkWs+7T3aOjo/Xggw/q9ddf1yeffKKWLVvquuuuU8+ePS/61PLzGTVqlLp166Zq1aqpdu3a6tixo+644w7VqVMnW5+389xDoHLlyrrjjjv03nvv6bHHHst0mhIlSmR5bfi53H///WrWrJl69OhxwZ/NjtKlSys+Pl5TpkzR8ePHlZaWphtuuCHL6Zs3b+6TOM5kZtm+BhwAAhFFNwAEoNDQUJUrV+68BdmaNWtUvnx5FSpUSJKy/GF65nWX27ZtU7t27VSjRg29/vrrioqKUqFChTR79my98cYbZz17Oatroc9XgJxPVteDZrW8zIafL4YaNWpIktauXavrr7/+wgI8h+x+126++g59Nd8zFS1a1KtQbN68ua666io9/vjjnqOh6enpcrlc+uabbzKNK+OR9tdee019+vTRV199pblz52rIkCEaPXq0li9fnukOCrfsXEN8Lq1atdK2bds8y33//ff1xhtv6N1331W/fv2y/FzJkiUlnd6ZUb58+XMuw31H/JdeeinTPpeSkqKDBw9mK97SpUsrf/78Wrhwob799ltNnz7d6+Z9qampOnHihHbu3Knw8HDPTqacuu2229S/f38lJCSoU6dOXtfrn+nAgQPZao9ixYqd9y7l53Lo0KEc7VgEgEDB3csBIEB17dpVO3bs0NKlSzMd//3332vnzp2eu4ZLp4+gHT58+Kxp3Uc73WbOnKnk5GT997//1d13363OnTsrPj7e65TzC3WuI1GZxZWSkqK9e/fmeHnZ1aJFC5UoUUKffvpptgqEihUrZvo87E2bNnnGS/87onxmXmd+1xfCF0fz3PFu3br1rHGZDcuuOnXqqGfPnvq///s/7dq1S5JUpUoVmZmio6MVHx9/1qtp06Ze84iNjdWTTz6pJUuW6Pvvv9dff/2ld999V9LFf7/n+i7Dw8N155136tNPP9Xu3btVp06dc94NXfrfzpsdO3acd9lVqlTxfDeZ9fEff/xRZcuWzdbLfdd393fcvXt3RUdHe15//fWXFi5cqOjoaH344Yfnje18/vWvfylfvnxavnz5ee9a3qhRo2zlcLHP2d6xY0eOb8oIAIGAI90AEKAefvhhTZ48WXfffbeWLFniOdImSQcPHtQ999yjkJAQDRo0yDO8SpUqSkxM1Jo1azyny+7du1dffvml17zdRyEzHg1NTEzUhAkTchxv0aJFJZ1dJLnjWrJkidew995776KPWmZHkSJFNGzYMD322GMaNmyYXnnllbMKso8//ljVqlVT48aN1blzZ40ZM0bLli1TXFycJOnYsWN67733VKlSJcXExHhykqQlS5aoXr16kk4fhX3vvfdyHOu5vsOcKleunGrXrq1JkyZp+PDhniOOixcv1tq1az1FeU48+uijmjRpkl5//XWNGTNG3bt31/DhwzVy5Eh9/PHHXt+zmengwYMqWbKkkpKSVKRIEa/nQcfGxipfvnxKTk6WdPqygFKlSmnJkiUaOnSoZ7rs3qm/aNGimX6P//zzj9e6VKxYMVWtWvWsR5qdqUGDBipUqJBWrlyp66677rzLd1/bnfGxcG45uaa7bdu2Z63HkjRgwABVrFhRTzzxhGJjY7M1z3MpVqyYxo0bp507d6pr167nnPZSXNOdmJiobdu26d57783xPADA3yi6ASBAVa1aVZMmTdKtt96q2NhY9e3bV9HR0dq5c6c++OADHTp0SFOnTlV0dLTnM7fccouGDRumf/3rXxoyZIiOHz+ucePGqVq1al7X7rZv316FChVS165ddffdd+vo0aMaP368ypQpk+Ojz/Xq1VP+/Pn10ksvKTExUUFBQZ7ngPfr10/33HOPevTooWuuuUa//fab5syZc8lOGX3kkUe0fv16vfbaa/ruu+90ww03KDIyUgkJCZoxY4Z+/vln/fjjj5Kkxx57zPPYpCFDhig8PFwfffSRduzYoS+++MLz+KZatWqpadOmGj58uA4ePKjw8HBNnTpVqampOY6zSpUqCgsL07vvvqvixYuraNGiatKkiVcb58QLL7ygbt26qXnz5rrzzjt16NAhvf3226pdu7aOHj2a4/nGxMSoc+fOev/99/XUU0+pSpUqeu655zR8+HDt3LlT119/vYoXL64dO3boyy+/1IABA/Twww9r4cKFGjRokG688UZVq1ZNqampmjx5svLnz+91vXK/fv304osvql+/fmrYsKGWLFmi33//PVuxNWjQQOPGjdNzzz2nqlWrqkyZMmrbtq1iYmLUpk0bNWjQQOHh4Vq5cqWmTZvmtfMqM8HBwWrfvr3mz5+vUaNGnXf57qPdH3300VnjcnJNd4UKFTK9t8LQoUMVERFx1mnsffr08fTbC30We+/evbM1XU6v6Z45c6Z+++03Sacfn7ZmzRo999xzkk7fnC/j9fXz58+Xmalbt245WhYABAQ/3TUdAJBNa9eutdtuu80iIyMtX758JsmCg4Nt/fr1mU4/d+5cq127thUqVMiqV69uH3/8caaPDPvvf/9rderUseDgYKtUqZK99NJL9uGHH571mKKsHknUunXrsx7JNH78eKtcubLlz5/f67FZaWlpNmzYMCtVqpQVKVLEOnToYFu3bs3ykWErVqzwmq87/gMHDngN7927txUtWvQ83+D/TJs2zdq3b2/h4eFWoEABK1u2rN188822aNEir+m2bdtmN9xwg4WFhVlwcLA1btzYZs2addb8tm3bZvHx8RYUFGQRERH2+OOP27x58zJ9ZFitWrXO+nxmj3j76quvLCYmxgoUKOD1yKysHhn2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bUNaWppSU1P1zDPPqEePHqpdu3ae/FHg5H7ntDZy4npEvwtcTux37kLu6NGj2r17t3r16qXbbrtN3bt3z5NtJP2vndwF6iuvvKKbb75Zbdq0yZOFt9PWo+wq4O8AELgy7oHKly+ffvnlF7355ptat26dChcurLi4OJ08eVJXXHGFnyPNvjNzWrdunf7v//5PP/zwgwoWLKgqVaooJSVFERERfo40e5yWj+S8nJyWj3R5bBs2b96sSZMm6euvv5bL5VLp0qXVvHlzlS5d2s+RZs/l0O+c1kZOXI/od4HH6f3u1KlT+vXXX/XSSy/pr7/+UkhIiLp3764TJ04oOjraz5Fm35nttH37dv3nP//R1KlTlZaWpoIFCyomJkbh4eF+jjR7nLYe5QRHupEl98rx4YcfaujQoWrRooUk6eGHH9b333+vn3/+Wa1bt1b16tX9GeYFcef02Wefafjw4WrUqJEOHjyogQMHavny5Vq/fr2uvvpqVahQwc+RZo/T8pGcl5PT8pGcvW2YNWuWRo4cqfr162vLli3q27evVqxYoV27dqlt27Z55geBk/ud09rIiesR/S5wObnfvfnmmxo8eLDi4+NVsmRJPfHEE5o3b54WL16sli1bql69ev4N9AK4c1q0aJFefvll1a9fX8uXL9dtt92mFStWKDExUW3btlVoaKifI80ep61HOWJAFlJSUmzChAlWuXJlu/fee2369OmecV999ZU1b97c9uzZY2ZmaWlp/grzgpw6dcpee+01i46Ott69e9vUqVM94z755BOLi4uzw4cPm5lZenq6v8LMtpSUFEflY+a8nJyWj5lztw1PPPGERUdHW48ePeyjjz7yjBs/frw1bdrUTp48aWZ5o52ctq0zc14bOXU9ot8FtuTkZEf2u5kzZ9qVV15pjzzyiH399deecfPnz7eWLVvali1bzCzv5JSWlmYDBw60KlWqWMeOHe29996zEydOmJnZG2+8YU2aNPFMmxf6ndPWo5zg9HKcxf7/KSAFCxZUmzZt1LFjR4WFhSk4ONgzzbRp01S+fHmFhYVJ+t/NKgJdgQIFFB8fr+7du6tkyZIqXry4Z9zMmTMVExPjydO9Vy6QudvIKflIzsvJSflcDtuGW265ReXKlfM6ZW/OnDmKi4vz5BLo7SQ5b1snOaeNLof1iH4XuAoVKqQWLVrohx9+yPP9zr0uFShQQM2aNdPPP/+s4sWLK3/+/J5ppkyZouLFiysyMlJS4Ofkli9fPrVv31533HGHKlas6IlfkhYvXqwOHTooLS1N+fLlyxP9rkCBAurQoYNj1qMc8W/Nj0Cye/duz16mc+0JnD59uoWGhtqaNWvMLLD3SP3zzz+eXM4V56effmrFixe3jRs3nndaf1q4cKGNGzfOXn31Vfv555+zjDOv5GPmvJyclo+ZM7cNP/zwg02bNs0mTZpku3fvznK6CRMmWNGiRW3r1q2XMLoL57RtnZnz2siJ6xH9LvD73TfffGMjR460Rx991L744ossv/u81O82bdpkR48eNbNzr0tff/21lSpVylasWGFmgZ3TqlWr7LvvvrOvv/7ac0Q7M+PGjbPixYvbH3/8cQmju3AZczjX955X1qPcQNENMzP7+OOPrXbt2vbxxx9bcnKymZ29kqSnp1taWpo98MADdt9991lKSkpAn6YzefJka9mypf34449ZrvDp6el24sQJGzBggD388MNmFrinHn3wwQdWrFgxa9++vYWHh1vdunWtT58+nnhTU1PzVD5mzsvJafmYOXPb8P7771tISIg1adLEChYsaI0aNbJnnnnGk5e7nZKSkqxnz5721FNPmVngtpPTtnVmzmsjJ65H9LvA73cTJkywwoUL280332zVq1e3WrVqWZs2bTwFkTufvNTvPv74Y7viiivs2WeftSNHjphZ1kXdk08+aX369LGkpKSALrjHjx9vJUuWtFq1apnL5bI2bdrYhx9+6BmflpZm6enpduDAAevevbuNHj3aMzwQTZo0ybp16+a5TCEzeWk9yi0U3bC5c+da+fLlrXz58ta4cWP77LPPsvxRkJCQYOXLl7cPPvjAH6Fm2zfffGNlypSx4OBgu+qqq855xHHHjh1Wrlw5r2vPAs327dstOjraJk6caGZmR48etX//+99Wp04da9eundeGKi/kY+a8nJyWj5kztw3r16+3K664wqZMmWInT560Q4cO2f33328NGjSwu+66yyuvdevWWbly5WzmzJl+jPjcnLatM3NeGzlxPaLfBX6/27t3r9WsWdPGjRtnZmYnT560mTNnWmxsrNWqVctzpNgs7/S7BQsWWHR0tNWtW9eaNWtmL774YpaF98GDB61SpUr25ptv+iPUbFuxYoWVKVPGPvvsM9u3b5/98ccfdt1111nTpk1t1KhRXnn99NNPVq5cOVuwYIEfIz63WbNmWUhIiLlcLmvfvr0lJCRkOW1eWI9yU964sAE+c+LECS1dulQdO3bUDz/8oDJlymj06NGaMWOGUlJS5HK5ZGZe0z///PO66667/Bj1uSUmJmrevHm69dZbtW3bNp06dUp33XWXVq5c6cklY05JSUl65JFHdPPNN/sr5PM6fPiwTpw4oSZNmkiSihYtqv79+2vkyJFKSEjQTTfd5MkpMTEx4PORnJeT0/Jx4rZBkvbt2yeXy6VWrVopKChIYWFhGjlypG6//Xb9+uuvevjhhz3THjx4UP369dO1117rx4iz5sRtneSsNnLiekS/C/x+J53uS4mJiapfv74kKSgoSJ06ddLkyZOVP39+tW3b1tNOx48fD/h+l5aWplWrVqlZs2b68ssvddVVV2natGkaO3asjh49KpfL5Xn+s3S6D44dO1aDBw/2vA9Eu3btUmhoqDp06KAyZcqoQoUK+uCDD9SoUSPNmjVLb731lmfa/fv364YbblDbtm39GHHWDhw4oBkzZuiuu+7Szz//rN9//1233nqr9u3bl+n0eWE9ylV+KPQRQNLT02316tX2/fffm9npU426dOli9erVs88++8xz/VlGx44d83w2EKWkpNicOXNs8eLFZnb6jom1a9e22rVr288//5zp6SvHjx83s8DNae/evValShV79913vYYnJyfbRx99ZHXr1rXJkyd7DTcL3HzMnJfTnj17rGrVqo7Jx4nbBjOz1atXW+XKle2bb74xs//FeuTIERsxYoQ1aNDAs+0wC+x2cuK2zsxZbeTE9SglJcXmzp1Lvwvgfmd2Or6aNWva8OHDzxq3ePFii4mJseeee85rerPAzcfs9O+GH374wcxOx3nfffdZw4YN7cUXX7SkpKSzpnf3u0D2zTffWHR0tK1bt87MTq9PZqfvl9C7d29r3ry51/XOKSkpZhaY7XT8+HGbPHmyZ3u3ZcsWq1ixol199dVZHvF2X+oQiPnkNoruy5i7g5/576lTp7x+FJw6dcoSExPt7bff9lusF8r9x8P9xz8lJcXzo8B9Q43Dhw/bZ5995rcYL8SxY8fshhtusA4dOtjatWu9xqWkpFirVq2sT58+foouZ5yWU1JSkvXo0cMR+Th523DgwAG76qqr7IYbbrB//vnHa9yxY8escuXK9uijj/opugvntG2dmfPayP0j2gnrUcYczJzV7/755x9r0KCBI/pdenq6paam2iOPPGItW7b0eoSWe/wdd9xhXbp0yRPFTlYxpqamehXex44dsyNHjnhdhx/o/vzzT4uIiLBBgwZ5hqWmppqZ2d9//22hoaH2yiuv+Cu8C3bmTeB+//13T+G9b98+MzM7dOiQLVy40B/h+RVF92XIvRc9M+4VPSUlxbp06WL169e38ePHW1xcnDVu3Dhgb3KwefNm++GHH2zLli2eZ4C6Y3X/OEhOTrbatWtbbGysffvttxYXF2edOnUKyA1zxjZy57Fp0yaLiIiw66+/3jZt2uQ1/fDhw61bt26e9gtETstp9erV9vXXX9v333/vuVnI+vXrLSIiwrp165bn8jFz9rZh69atdvDgQTMzW758uRUqVMjuvffes46O3HXXXXbXXXf5I9Rscdq2zsx5bZRx2+A+unNmsZrX1qPMjsi75dV+lzEn9/e+cuVKCwoKsvvuuy/P9bvExETP/93f+c6dO61p06bWvn17mzt3rtf0b7zxhrVq1SqgjwZnzOlM7r9Jp06dsoEDB1rjxo3tqaeesri4OKtSpUrA/q3dtWuXbdiwwQ4fPuz5mzt9+nTLnz+/15kH7ja89tprA3pnT8Z83AW3+8Zvbps3b7aKFSta27Ztbe3atda0aVO7/fbbA3bb4CsU3ZeZL774wvr162ebN2/OcpqMe7A7dOhgLpfL6tSpE7CntLz//vsWFRVl5cqVs0qVKlm7du08j7zIuBfe7PRG2n13yFq1agVkTpm1kbtNVq9ebWFhYda1a1f773//a6mpqXbo0CFr2bKl3Xvvvf4K+bycltP48eMtMjLSoqOjrWLFila1alWbN2+emeXNfMwuj21D27Zt7ZdffjEzsxkzZlihQoWsZ8+e9ttvv1l6erodP37cGjdubMOGDfNz5Jlz2rbOzHltlNm24bvvvvOaJq+tR1999ZU9//zz57whUl7rd5nl5C7SZs6caUFBQXmq33322WfWrl07r0djufPZtGmTXXXVVRYfH29vvfWWJScn2969e61du3Z2xx13+DPsczozp8y4c0xPT7e+ffuay+Wyq666ytPvAm0n1ocffmhVq1a1yMhIq1q1qtff3DFjxli+fPls2LBh9vfff5vZ6R1Z9evXtxdeeMGfYWcpYz5VqlSx/v372++//25m3m1jZrZ161arVKmSuVwuq1GjhqeNLicU3ZeRr776yvLnz29XXHGFDRkyxLZs2ZLltGlpaXb8+HFr0aKFNW3a1PMjwf1voFiyZIkVK1bMJk+ebNu3b7cpU6ZY165drVixYl7X0Jmdzik5OdmaN29uzZo1C8icsmqj9PR0T5zr1q2zFi1aWO3ate2KK66wBg0aWGxsbMBuwJyW008//WRhYWE2depUO3DggC1dutT69Olj+fPn9zziY82aNda8efM8kY/Z5bVtKFq0qOe6zEWLFnnap3bt2hYXF2e1atUKuFzMnLetM3NeG2W1bShQoIBNmjTJa9q8sh5Nnz7dXC6XlSxZ0l599VXP6aGZySv97lw5uQuEpUuXWvny5fNEv/v666+tWLFiVrlyZbv++utt5cqVZub9N3br1q12xx132JVXXmmhoaFWp04dq1evXsDuFMkqp8ykp6fbkSNHrEWLFta4ceOA7Xfz5s2zokWL2vjx42316tU2evRoa9u2rVWvXt1zPfekSZOsSJEi1rx5c2vbtq21bNnSYmJiAi4Xs8zzadeunVWvXt2zMzjj2QaHDh2yevXqWfPmzQO2jXyNovsysWfPHuvQoYM99thj9sorr1j9+vVt4MCB5/xxPWzYMCtVqpRnoxyIK8fkyZOtdevWXnszd+7caT179rTChQvbqlWrzOx/e30HDRpkERERAZnT+doo4x/Q/fv3248//mhjxoyxqVOnBuwGzIk5zZ492+rXr+916mFKSoo99thjVqBAAfvqq6/M7HTuP/zwQ8DnczluG4KDg+2nn34ys9OPM5oyZYo9/fTTNnbs2IBtJydt69yc1kbn2jYULFjQc12t+9TLQF+P/vjjD2vbtq2NGDHCHnnkEYuKirKXXnopy8I7L/S77OTkLhR27doV8P3uwIED1qVLFxs6dKhNnDjR4uPj7dprr8208E5KSrKdO3faxx9/bHPnzvU6PTuQnC+nzIwaNcpKlCgRsP3OzOy1116zbt26eQ1bunSpdenSxaKjo23jxo1mdvrMhOeee84GDx5so0aN8uQSaKfLZ5XPtdde65VPenq6nTx50vr27Wvly5cP6DbyNYruy0RKSop9+OGHtmjRIjMze/vtt8/74/rQoUMBu1F2+7//+z8rVqzYWdf9/PXXX3bjjTdaTEyM/fXXX2Z2esXfsGFDwOaU3TbK6nSpQNsgmzkzpy+++MJcLpfntER37O47qZYoUcJzetWZAjGfy3HbcMMNN1jNmjXtjz/+yPSzgdhOTtrWuTmtjbKzbch4F+LDhw8HdBvt37/f3njjDVu2bJmZmT3xxBNWoUKFLAvv1NRUW79+vSNyyqp/BWK/mzZtms2ZM8fMTh/Fz6xIzUt/Y82yl9OZArnfmZ3eMRAVFXXWNfQ//fSTderUya699tpz7tAKNOfKp3Pnznbttdd6bkiYnJxs8+bNC8gdV5cSRfdlwH3a0Jk3QnH/uL7vvvs8P67//vtv27Vrl9d0gXZNTEabNm2yBg0a2IgRI+zIkSNe4xYvXmx16tTxPP4jo0DbgF1oG+3evfuSx5hTZ55SnddzOnz4sDVv3tx69+7tue7KvY5s377dGjVqZGPHjvUaHuiy20ZO2zbMnj3bzAI7D/e2YcOGDY7Y1pldWE55oY3ccrptCOTc3De2c8tYpO7fv9/MTu+EO/N670Dsd245zSmv+OKLL84qUvft22fbtm3zc2Q5l1VO27dv95ouENcld0zz5s2zunXr2qRJkzxPnXCbNGmSVatWzfPkk0DMw+1C8nGfNp9RIG8bfI2i28H++usv+/vvvz13VnbL+APb/eN60KBBtmzZMmvRooVdd911lzrUC5Zxg/TAAw9Y3bp17cMPP/S6+3J6erpVqVLFnn/+eX+EmC05baMzT+kJRGf+0ci4oc2LOWXMZ8yYMZ47pR46dMhruqZNm9pDDz10iaPLmQttI7YNl05m24YHHnjA6tSpkyfzMXNmTmbO2jYcPHjQjh49etaduzP+TXIXqS+//LKtXbvWrrnmmoC+SaQTczI7e/ud8f0XX3xh11xzjXXt2tXmzp1rDRs2tEaNGl3qEC+Yk3LKrN9df/31VqNGDfvuu++8/t6mpqZaqVKl7N133/VHqNnitHz8gaLboSZMmGD169e3ChUqWGxsrL300ktef2AyrhzvvPOO1a1b14oUKRLQN3uaM2eOTZ061fM+Y5w33HCDxcbG2htvvOF5ZMGRI0escePGnptbBZrLoY3OvDlLxj+geSGnL7/80t58803P+4wxPvTQQ9agQQO7//77PY9uOnHihLVo0cJefvnlSx5rdjmtjcycv23IeOfam2++2WrVqpWn8jFzXk5O3DZMmjTJ2rRpY5UrV7Zrr732rO8+49+kp59+2ipUqGClS5cO6DsROy2nM/vdmUVqxu35l19+aVdffbW5XC6rX7/+WUcjA4UTczqz37333nuecY0bN7Yrr7zSZsyY4TnN+sCBA1avXj2bMWOGv0I+J6fl4y8U3Q40c+ZMK1y4sH344Yc2adIkGz16tAUFBdmtt97qdX2ce8N27NgxK1++fEDfQfXzzz/3PFZlypQpnuEZN7j9+vWz+vXrW/369W3IkCHWrFkzq127dsDlYnZ5tVFWe64DPSf39ZmlS5e2N954wzM8Y5979tlnrUmTJhYREWE333yzNWzYMGDvcGvmvDYyu3y2DTfeeKOngBswYIDVq1cvT+Rj5rycnLhtmDZtmgUHB9vbb79tL7/8sg0cONDy589vDz/8sFfx6d42JCcnW8mSJQP6LuVOyymrfpdVkXrkyBGrXLmyNWnSJCDzMXNmTln1u/vvv98zTXx8vNWuXdu6detmzz33nLVp08bq1KkTkKdeOy0ff6LodqBhw4ZZjx49vIYtW7bMihcvbjfccIPneqb09HQ7evSoXXXVVVapUqWA3YD9+uuv1rBhQ+vfv7/deuut1rx5c/v444894zP+0Jk5c6YNGTLEbr31VnvggQcC9q6Pl1sbnfkHNNBzcj/CbODAgfbwww9b9erV7dVXX/WMz9jnVq9ebc8++6wNHjzYRowYEbB9zmltZHb5bRuuv/56T7wzZszIE/mYOSsnJ24bzMzuvvtu69+/v+f9iRMn7NNPP7XChQt7/bhOT0+3xMREa9iwoUVHRwfstsHMWTmdr9+duf0+fvy4derUya688sqAvVu0E3MyO3e/y3jJwptvvmm33HKLdezY0fr16+f1rPtA4rR8/Imi20HcewJ79uxpnTp18gx3d/yVK1da0aJFbdiwYV6f++yzzwJ6A/b777/bLbfcYhs3brR169bZrbfeai1atPD6cX2u08ACKafLuY3OPI05kHP666+/7M4777Rff/3V/vzzTxs2bNhZPwjySp9zc1obmV2e24ZzXRMcSPmYOTMnJ24bUlNTLT4+3nr27OkZ5m67adOmWf78+b2OQpqdvvQkkLcNTsspO/3uzCL166+/Dth8zJyZU3b63ZmXmGTcXgRaTk7Lx98ouh1o2rRpFhQU5HUnW3fHnzx5soWHh3ue6ZpRIK0c7pXa/a/7jqJmp49uZfbj+ujRo5c2yItwubZRxhsluQVSTmb/y8d92qvZ6TsPZ/aDIDEx8axCNZA4sY3YNoSf87E5gcgpOTlx2+D2zjvvWNmyZT2P0nJLS0uz559/3mJiYs66U7RZYG4b3JyQk9mF9bukpKSzvodAy8fMWTnlpN9ldif5QNleOC2fQJJPcITU1FTP/1u0aKEbb7xRzz//vH744QdJUv78+SVJ9evXV4ECBXT48OGz5lGgQIFLEmt2pKenS5JcLpckqXTp0jIzpaenq169eho2bJjKly+vd999V59++qmOHz+u1q1ba/r06f4M+5xoo+Nq1arVWW0USDmlpqZ68gkNDZV0Os/o6Gjde++96tatm8aPH6833nhDycnJio+P1/jx4/0Z8jk5sY3YNhRQYmKiX+K8EE7LyanbBrdmzZqpdu3aevvtt7V+/XrP8Hz58ikuLk5//fVXnvmb5OaEnC6037Vr1+6sfhdI+UjOyykn/S6z7Z37O/E3p+UTUPxb8+Ni/fDDD57/Z9zzN3fuXOvYsaO1adPG5s+f7xl+8OBBi4mJyfR5roFi2rRpdvPNN1u3bt1s6NChdvDgQc8es4ynGq1evdpuu+02i4uLs8qVK1vFihUD8m6jtFHeaqNzXX+0c+dOe+yxx6xatWpWtmxZq1SpUkDmY+a8NjJzXk5O3DY4LSenbxsy3mH9s88+s/r161uvXr1sxYoVnun/+OMPq127ti1fvtxfIZ+X03JyYr9zYk5O63dOyyfQUHTnYZ9++qm5XC5r2bKl54dnxpu4zJ4923r06GFlypSxp59+2saOHWvXXHON1a9fP2BvbPDxxx9bUFCQDRkyxPr3728VKlSwatWq2YwZMzyPksn443rBggVWsGDBgL27Mm2UN9voXPGtWLHCQkNDLS4uLiDzMXNeG5k5LycnbhucltPlsm2oWrWqzZw508zMpkyZYi1btrR69erZ22+/bdOnT7drrrnGGjdufNb1tYHCaTk5sd85MSen9Tun5ROIKLrzqOXLl1udOnWsZ8+eFhsba23atMn0R86mTZvstddesypVqlibNm2sR48eAXlHwdTUVEtKSrJWrVrZiy++6DW8Q4cOVqNGDfvPf/7jtdH9+++/rWXLlhYbGxuQG2XaKG+3UWZxHjp0yNq3b281a9YMyHyc2EZOzMlp2wYz5+V0uW0brrzySps+fbqZmS1evNgeeughCwsLs7i4OOvUqZOnjQLpx7UTc3JavzNzXk5O63dOyyeQUXTnURMmTLA+ffrY2rVrbc6cORYTE+O1ITt58qTX9EePHvVaIQJpA+Z24sQJa9CggY0ZM8bMvHO49tprrWrVqvb77797hu3cudOuvfbagL2TJW2U99vozHj/+usvu/vuuwM2HzPntZGZ83Jy4rbBaTldjtuG6Oho27p1q2fY33//bUePHs3WkUl/cVpOTux3TszJaf3OafkEKoruPOTuu++28ePHm9npPVDuayhSU1Nt9uzZng2Z+4dMamqqnTp16qy9T4F0R8G7777b3n//fc/7Fi1a2HXXXed5n3HFj4mJseuvvz7T+QTKCk8bOa+N0tLSLDU19ayjcIGSj5nz2sjMeTk5ddvgpJzYNsR4jcsokI5iOS0np/Y7J+bktH7npHzyAoruPOLUqVP28ssvW3R0tE2ePNkz3P1jJSUlxb755hvPhszM7Pjx4zZ06FDbtGmTX2I+n8xy+v77761EiRL21FNPeaY7fvy4mZ2+JqhKlSr2559/BsyPtIxoI+e20f33328bN270S8zn47Q2MnNeTpfLtsEs7+bEtiHw1yMz5+V0ufQ7M+fl5LR+l5fzySsouvOQlJQUe+edd6xixYo2ZcoUz3D3nkH3hqx27drWsmVLa9GihUVGRgbUdXJnypjTp59+amZmzz33nEVHR9vIkSO9pp0xY4bVqlXLDhw44I9Qs4U2oo38wWltZOa8nJze75yQk9PyMXPeemTmvJyc3u+cmJPT+p0T8skLKLrzmJSUFBs7dmyWG7K0tDTPXSLj4uLyxA0OUlJS7O2337YKFSrYjBkzzMzsmWeesTJlylifPn1szZo19ttvv1nnzp2tQ4cOAb+XjTaijfzBaW1k5rycnNrvnJST0/Ixc956ZOa8nJza75yYk9P6nZPyCXQU3XlQcnJyphuytLQ0S0pKsiZNmgTsXXuzkpycfNaKP23aNKtUqZJFRkbalVdeac2aNcsTG2Uz2siMNvIHp7WRmfNycmq/c1JOTsvHzHnrkZnzcnJqv3NiTk7rd07KJ5BRdOdRWe1B/OSTT6xDhw4BfdfHrGTc4/af//zHzE7fUfGnn36ytWvXelb0vJITbRT4aKO8wWk5ObXfOSknp+Vj5rz1yMx5OTm13zkxJ6f1OyflE6gouvOwjBuyTz75xMz+d3dYs7y5crhX/IoVK9qkSZPOGp/X9rDRRoGPNsobnJaTU/udk3JyWj5mzluPzJyXk1P7nRNzclq/c1I+gYiiO4/LuCHLeJfIQL4ZxflktVc0r15LQhsFPtoob3BaTk7vd07IyWn5mDlvPTJzXk5O73dOzMlp/c4J+QQaim4HyLiSuO9AmNc5LSen5WPmvJyclo8ZOeUFTsvHzHk5OS0fM3LKC5yWjxk55QVOyyeQUHQ7hPvW/5GRkTZ16lR/h5MrnJaT0/Ixc15OTsvHjJzyAqflY+a8nJyWjxk55QVOy8eMnPICp+UTKAoIjlCwYEH17dtX+fLl04oVK3TdddepcOHC/g7rojgtJ6flIzkvJ6flI5FTXuC0fCTn5eS0fCRyyguclo9ETnmB0/IJFC4zM38HgdyTlpam5ORkFSlSxN+h5Bqn5eS0fCTn5eS0fCRyyguclo/kvJyclo9ETnmB0/KRyCkvcFo+/kbRDQAAAACAj+TzdwAAAAAAADgVRTcAAAAAAD5C0Q0AAAAAgI9QdAMAAAAA4CMU3QAA/H8jRoxQvXr1/B1Grlm0aJFcLpcOHz7s71AAALhsUXQDAC6ZhIQEDR48WJUrV1ZQUJCioqLUtWtXLViw4JLH4nK5NGPGDK9hDz/88CWJZcSIEXK5XHK5XMqfP7+ioqI0YMAAHTx4MFeX06xZM+3du1ehoaHnnfZSFOjunJcvX+41PDk5WSVLlpTL5dKiRYt8tvzLwcSJExUWFubvMAAAGRTwdwAAgMvDzp071bx5c4WFhemVV15RbGysTp06pTlz5mjgwIHatGmTv0NUsWLFVKxYsUuyrFq1amn+/PlKS0vTxo0bdddddykxMVGfffZZri2jUKFCioyMzLX5ZYeZKS0tTQUKZP4TIyoqShMmTFDTpk09w7788ksVK1Ys13c6+MKpU6dUsGBBf4cBAMhDONINALgk7rvvPrlcLv3888/q0aOHqlWrplq1aunBBx/0OvK5a9cudevWTcWKFVNISIhuuukm7du3zzO+T58+uv76673mPXToULVp08bzvk2bNhoyZIgeffRRhYeHKzIyUiNGjPCMr1SpkiTpX//6l1wul+f9maeXu5f16quvqmzZsipZsqQGDhyoU6dOeabZu3evunTposKFCys6OlpTpkxRpUqVNGbMmHN+HwUKFFBkZKSuuOIKxcfH68Ybb9S8efO8pnn//fdVs2ZNBQcHq0aNGnrnnXe8xv/444+qV6+egoOD1bBhQ82YMUMul0urV6+WdPbR6z/++ENdu3ZViRIlVLRoUdWqVUuzZ8/Wzp07dfXVV0uSSpQoIZfLpT59+kiS0tPTNXr0aEVHR6tw4cKqW7eupk2b5onBvYxvvvlGDRo0UFBQkJYuXZpl3r1799bUqVN14sQJz7APP/xQvXv3Pmva3bt366abblJYWJjCw8PVrVs37dy50zN+xYoVuuaaa1SqVCmFhoaqdevW+uWXXzzjzUwjRoxQhQoVFBQUpHLlymnIkCGe8Zmd7RAWFqaJEydKOr2jyOVy6bPPPlPr1q0VHBysTz755Lxt4/7cf/7zH7Vs2VKFCxdWo0aN9Pvvv2vFihVq2LChihUrpk6dOunAgQNey8/OfKdPn66rr75aRYoUUd26dbVs2TJPW9x5551KTEz0nFWQsd8DAPzEAADwsX/++cdcLpe98MIL55wuLS3N6tWrZy1atLCVK1fa8uXLrUGDBta6dWvPNL1797Zu3bp5fe7+++/3mqZ169YWEhJiI0aMsN9//90++ugjc7lcNnfuXDMz279/v0myCRMm2N69e23//v1mZvbMM89Y3bp1vZYVEhJi99xzj23cuNFmzpxpRYoUsffee88zTXx8vNWrV8+WL19uq1atstatW1vhwoXtjTfeyDLPM5ezY8cOq1WrlkVERHiGffzxx1a2bFn74osvbPv27fbFF19YeHi4TZw40czMEhMTLTw83Hr27Gnr16+32bNnW7Vq1UyS/frrr2Zm9t1335kkO3TokJmZdenSxa655hpbs2aNbdu2zWbOnGmLFy+21NRU++KLL0ySbd682fbu3WuHDx82M7PnnnvOatSoYd9++61t27bNJkyYYEFBQbZo0SKvZdSpU8fmzp1rW7dutX/++SfTvCXZl19+aXXq1LHJkyebmdkff/xhQUFB9vvvv5sk++6778zMLCUlxWrWrGl33XWXrVmzxjZs2GC33XabVa9e3ZKTk83MbMGCBTZ58mTbuHGjbdiwwfr27WsRERGWlJRkZmaff/65hYSE2OzZs+2PP/6wn376yavt3PFkFBoaahMmTPC0iySrVKmSpx327Nlz3rZxf879vW3YsMGaNm1qDRo0sDZt2tjSpUvtl19+sapVq9o999yT7TbPON9Zs2bZ5s2b7YYbbrCKFSvaqVOnLDk52caMGWMhISG2d+9e27t3rx05ciTLfggAuDQougEAPvfTTz+ZJJs+ffo5p5s7d67lz5/fdu3a5Rm2fv16k2Q///yzmWW/6G7RooXXNI0aNbJhw4Z53mdWcGVWdFesWNFSU1M9w2688Ua7+eabzcxs48aNJslWrFjhGb9lyxaTdN6iO1++fFa0aFELDg42SSbJXn/9dc80VapUsSlTpnh97tlnn7W4uDgzMxs3bpyVLFnSTpw44Rk/fvz4cxbdsbGxNmLEiExjOnNaM7OTJ09akSJF7Mcff/Satm/fvnbrrbd6fW7GjBlZ5uvm/s7HjBljV199tZmZjRw50v71r3/ZoUOHvIruyZMnW/Xq1S09Pd3z+eTkZCtcuLDNmTMn0/mnpaVZ8eLFbebMmWZm9tprr1m1atUsJSXlnPFklFnRPWbMGK9pztc27s+9//77nvGffvqpSbIFCxZ4ho0ePdqqV69+UfN1rx8bN240M7MJEyZYaGhopvkCAPyDa7oBAD5nZtmabuPGjYqKilJUVJRnWExMjMLCwrRx40Y1atQo28usU6eO1/uyZctq//792f68W61atZQ/f36v+axdu1aStHnzZhUoUEBXXXWVZ3zVqlVVokSJ8863evXq+u9//6uTJ0/q448/1urVqzV48GBJ0rFjx7Rt2zb17dtX/fv393wmNTXVc1O0zZs3q06dOgoODvaMb9y48TmXOWTIEN17772aO3eu4uPj1aNHj7O+p4y2bt2q48eP65prrvEanpKSovr163sNa9iw4XlzduvZs6cee+wxbd++XRMnTtSbb7551jS//fabtm7dquLFi3sNP3nypLZt2yZJ2rdvn5588kktWrRI+/fvV1pamo4fP65du3ZJkm688UaNGTNGlStXVseOHdW5c2d17do1y+vNs5Ixt+y0jVvG7zYiIkKSFBsb6zXM3SdzOt+yZctKkvbv368aNWpcUF4AgEuDohsA4HNXXnmlXC5XrtwsLV++fGcV8RmvsXY782ZXLpdL6enpF7y83JrPmQoVKqSqVatKkl588UV16dJFI0eO1LPPPqujR49KksaPH68mTZp4fS7jDoAL1a9fP3Xo0EFff/215s6dq9GjR+u1117zFPtncsfx9ddf64orrvAaFxQU5PW+aNGi2Y6jZMmSuvbaa9W3b1+dPHlSnTp10pEjR85adoMGDTzXUGdUunRpSaevD//nn3/073//WxUrVlRQUJDi4uKUkpIi6fRN2zZv3qz58+dr3rx5uu+++/TKK69o8eLFKliwoFwuV7b6UsbcLqRtMvYdl8uV6TB3X7rY+eZGnwQA+AY3UgMA+Fx4eLg6dOigsWPH6tixY2eNd9/oq2bNmtq9e7d2797tGbdhwwYdPnxYMTExkk4XXHv37vX6vPvGYReiYMGCSktLu+DPZVS9enWlpqbq119/9QzbunWrDh06dMHzevLJJ/Xqq69qz549ioiIULly5bR9+3ZVrVrV6xUdHe1Z9tq1a5WcnOyZx4oVK867nKioKN1zzz2aPn26HnroIY0fP17S6Z0Akry+k5iYGAUFBWnXrl1nxZHxbIScuOuuu7Ro0SL16tUr0x0JV111lbZs2aIyZcqctWz3kd8ffvhBQ4YMUefOnVWrVi0FBQXp77//9ppP4cKF1bVrV7355ptatGiRli1b5jlT4cy+tGXLFh0/fvyccWenbXIit+ZbqFChi+7XAIDcRdENALgkxo4dq7S0NDVu3FhffPGFtmzZoo0bN+rNN99UXFycJCk+Pl6xsbG6/fbb9csvv+jnn39Wr1691Lp1a88pvm3bttXKlSs1adIkbdmyRc8884zWrVt3wfFUqlRJCxYsUEJCQo6KZEmqUaOG4uPjNWDAAP3888/69ddfNWDAABUuXNhzBDK74uLiVKdOHb3wwguSpJEjR2r06NF688039fvvv2vt2rWaMGGCXn/9dUnSbbfdpvT0dA0YMEAbN27UnDlz9Oqrr0pSlsseOnSo5syZox07duiXX37Rd999p5o1a0qSKlasKJfLpVmzZunAgQM6evSoihcvrocfflgPPPCAPvroI23btk2//PKL3nrrLX300Uc5+s7cOnbsqAMHDmjUqFGZjr/99ttVqlQpdevWTd9//7127NihRYsWaciQIfrzzz8lnT6DYvLkydq4caN++ukn3X777SpcuLBnHhMnTtQHH3ygdevWafv27fr4449VuHBhVaxYUdLpvvT222/r119/1cqVK3XPPfdk63Fg52ubnMqN+VaqVElHjx7VggUL9Pfff593JwIAwPcougEAl0TlypX1yy+/6Oqrr9ZDDz2k2rVr65prrtGCBQs0btw4SaeLxa+++kolSpRQq1atFB8fr8qVK3s9u7pDhw566qmn9Oijj6pRo0Y6cuSIevXqdcHxvPbaa5o3b56ioqLOuj75QkyaNEkRERFq1aqV/vWvf6l///4qXry417XW2fXAAw/o/fff1+7du9WvXz+9//77mjBhgmJjY9W6dWtNnDjRc9QzJCREM2fO1OrVq1WvXj098cQTevrppyUpy2WnpaVp4MCBqlmzpjp27Khq1ap5Hkl1xRVXaOTIkXrssccUERGhQYMGSZKeffZZPfXUUxo9erTnc19//fVFHdWVTrd1qVKlPEfYz1SkSBEtWbJEFSpUUPfu3VWzZk3P6eghISGSpA8++ECHDh3SVVddpTvuuENDhgxRmTJlPPMICwvT+PHj1bx5c9WpU0fz58/XzJkzVbJkSUmn+0BUVJRatmyp2267TQ8//LCKFCly3tjP1zY5lRvzbdasme655x7dfPPNKl26tF5++eWLigkAcPFclt272wAAgPP6888/FRUVpfnz56tdu3aXdNmffPKJ5znNGY/4AgAA/+FGagAAXISFCxfq6NGjio2N1d69e/Xoo4+qUqVKatWqlc+XPWnSJFWuXFlXXHGFfvvtNw0bNkw33XQTBTcAAAGEohsAgItw6tQpPf7449q+fbuKFy+uZs2a6ZNPPsnWtcEXKyEhQU8//bQSEhJUtmxZ3XjjjXr++ed9vlwAAJB9nF4OAAAAAICPcCM1AAAAAAB8hKIbAAAAAAAfoegGAAAAAMBHKLoBAAAAAPARim4AAAAAAHyEohsAAAAAAB+h6AYAAAAAwEcougEAAAAA8BGKbgAAAAAAfOT/AfsbXIsOtbMKAAAAAElFTkSuQmCC", "text/plain": [ "

" ] @@ -263,7 +333,7 @@ } ], "source": [ - "# Visualize counting register results\n", + "# Visualize counting register distribution\n", "counting_results = results[\"counting_register_results\"]\n", "sorted_results = sorted(counting_results.items(), key=lambda x: x[1], reverse=True)\n", "\n", @@ -282,7 +352,25 @@ }, { "cell_type": "markdown", - "id": "fa08c609-3033-41de-9cf4-3cc669412740", + "id": "estimate-accuracy", + "metadata": {}, + "source": [ + "### Understanding the Estimate Accuracy\n", + "\n", + "The estimate $M \\approx 1.23$ rather than exactly $M = 1$ arises for two reasons:\n", + "\n", + "1. **Not in an eigenstate:** QPE works perfectly when the input state is an eigenstate of the operator. However, the uniform superposition $|s\\rangle = H^{\\otimes n}|0\\rangle^{\\otimes n}$ that we prepare is generally **not** an eigenstate of $G$. Instead, it is a superposition of both eigenstates:\n", + "\n", + "$$|s\\rangle = \\sin(\\theta/2)|\\beta\\rangle + \\cos(\\theta/2)|\\alpha\\rangle$$\n", + "\n", + " where $|\\alpha\\rangle$ and $|\\beta\\rangle$ are the eigenstates of $G$ with eigenvalues $e^{+i\\theta}$ and $e^{-i\\theta}$ respectively. Because we start in this superposition, QPE produces **both** phase estimates $\\varphi$ and $1 - \\varphi$, which is why we see two dominant peaks in the histogram.\n", + "\n", + "2. **Finite precision:** When the true phase $\\theta/(2\\pi)$ is not exactly representable as a $t$-bit fraction $y/2^t$, there is a discretization error. Using more counting qubits (larger $t$) reduces this error and gives a more precise estimate of $M$." + ] + }, + { + "cell_type": "markdown", + "id": "fa08c609", "metadata": {}, "source": [ "## Example 2: Counting Multiple Marked Items\n", @@ -292,8 +380,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "e8901c56-66f3-4428-89a9-ceee58082bb1", + "execution_count": 7, + "id": "e8901c56", "metadata": {}, "outputs": [ { @@ -301,44 +389,88 @@ "output_type": "stream", "text": [ "Quantum Counting Results (N=8, M=2):\n", - "Measurement counts: Counter({'11011101': 184, '00101010': 178, '00101101': 173, '11011010': 167, '11011011': 62, '00101000': 61, '11011110': 59, '00101111': 57, '11011100': 57, '00101001': 55, '11011000': 55, '00101110': 53, '11011001': 47, '00101011': 47, '11011111': 46, '11010101': 44, '00101100': 42, '00110101': 41, '11010010': 37, '00110010': 34, '00110000': 18, '11010000': 18, '00110100': 18, '11010111': 18, '00100101': 17, '00110110': 16, '11010110': 15, '11100101': 15, '11010001': 15, '00100010': 14, '00110001': 13, '11100010': 13, '00110111': 13, '11010100': 12, '11010011': 9, '00110011': 9, '00011010': 9, '00111010': 8, '11100111': 8, '11001001': 7, '11001101': 7, '11001100': 6, '11001010': 6, '00111001': 6, '00100100': 6, '00100001': 6, '11100000': 5, '11100011': 5, '00111111': 5, '01000101': 5, '00100110': 4, '00010101': 4, '11110010': 4, '00010010': 4, '11111010': 4, '11100100': 4, '11001011': 4, '11000010': 4, '00111101': 4, '00011101': 4, '01000000': 3, '01001001': 3, '11101010': 3, '10010000': 3, '00100111': 3, '01000010': 3, '00111110': 3, '01100001': 2, '11101101': 2, '01011111': 2, '11000101': 2, '01111001': 2, '01001101': 2, '01000111': 2, '00011001': 2, '11001000': 2, '11101111': 2, '11100110': 2, '01011101': 2, '00000110': 2, '00111011': 2, '01011010': 2, '00011110': 2, '11101110': 2, '01000100': 2, '10101110': 2, '00000010': 2, '11000000': 2, '00111100': 2, '01001010': 2, '00000101': 2, '00001101': 2, '01010011': 2, '00100000': 2, '00111000': 2, '11101001': 2, '11001111': 2, '01111011': 1, '10011001': 1, '10001110': 1, '11101011': 1, '01111110': 1, '10110001': 1, '11100001': 1, '11000111': 1, '11000001': 1, '10101011': 1, '00001111': 1, '01100101': 1, '11000011': 1, '01111010': 1, '10101111': 1, '10001010': 1, '10011101': 1, '01011000': 1, '11110100': 1, '10011000': 1, '01101011': 1, '01101001': 1, '10110011': 1, '01001011': 1, '01001100': 1, '10111100': 1, '00010111': 1, '00010001': 1, '11110011': 1, '01000011': 1, '10111101': 1, '00001000': 1, '11111101': 1, '00001010': 1, '00001100': 1, '10100100': 1, '01000110': 1, '10011100': 1, '11111110': 1, '01001111': 1, '11000100': 1, '10011011': 1, '00011000': 1, '10101001': 1, '11110111': 1, '00000011': 1, '11101000': 1, '01110110': 1, '11001110': 1, '11110101': 1, '10111110': 1, '11000110': 1, '00011100': 1, '10111000': 1, '01000001': 1, '10111010': 1, '01100110': 1, '01101000': 1})\n", - "Counting register results: {'11010': 168, '00101': 666, '00110': 162, '01100': 4, '11100': 53, '11011': 677, '00100': 52, '01111': 5, '11001': 35, '10011': 5, '10001': 2, '11101': 13, '00010': 10, '11110': 8, '01011': 7, '11000': 13, '00111': 32, '10110': 2, '01001': 10, '01000': 18, '00011': 19, '11111': 6, '10101': 5, '00001': 6, '00000': 7, '10010': 3, '01101': 3, '01010': 2, '10111': 5, '10100': 1, '01110': 1}\n", - "Phase estimates: [0.8125, 0.15625, 0.1875, 0.375, 0.875, 0.84375, 0.125, 0.46875, 0.78125, 0.59375, 0.53125, 0.90625, 0.0625, 0.9375, 0.34375, 0.75, 0.21875, 0.6875, 0.28125, 0.25, 0.09375, 0.96875, 0.65625, 0.03125, 0.0, 0.5625, 0.40625, 0.3125, 0.71875, 0.625, 0.4375]\n", - "Estimated item counts: [np.float64(2.4692662705396407), np.float64(1.777719067921591), np.float64(2.4692662705396407), np.float64(6.82842712474619), np.float64(1.1715728752538106), np.float64(1.7777190679215926), np.float64(1.17157287525381), np.float64(7.923141121612921), np.float64(3.219638711935487), np.float64(7.325878449210182), np.float64(7.923141121612923), np.float64(0.6741215507898192), np.float64(0.30448186995485294), np.float64(0.30448186995485405), np.float64(6.222280932078408), np.float64(4.000000000000001), np.float64(3.219638711935487), np.float64(5.530733729460362), np.float64(4.780361288064514), np.float64(3.999999999999999), np.float64(0.6741215507898188), np.float64(0.07685887838707856), np.float64(6.22228093207841), np.float64(0.07685887838707821), np.float64(0.0), np.float64(7.695518130045147), np.float64(7.325878449210182), np.float64(5.530733729460359), np.float64(4.7803612880645145), np.float64(6.82842712474619), np.float64(7.695518130045147)]\n", - "Best estimate of M: 1.7777190679215926\n", - "Search space size N: 8\n", + "Search space size N = 8\n", + "\n", + "Counting register distribution (top outcomes):\n", + " |01011>: 687 counts -> phase = 0.1562, M ~ 1.7777\n", + " |10101>: 671 counts -> phase = 0.1562, M ~ 1.7777\n", + " |10110>: 204 counts -> phase = 0.1875, M ~ 2.4693\n", + " |01010>: 173 counts -> phase = 0.1875, M ~ 2.4693\n", + " |01100>: 51 counts -> phase = 0.1250, M ~ 1.1716\n", + " |10100>: 39 counts -> phase = 0.1250, M ~ 1.1716\n", + " ... (23 more outcomes)\n", + "\n", + "Best estimate of M: 1.777719067921591\n", "\n", "Actual M = 2\n", - "Estimated M ≈ 1.7777\n" + "Estimated M = 1.7777\n" ] } ], "source": [ "n_counting = 5\n", "n_search = 3\n", - "marked_states = [2, 5]\n", - "N = 2**n_search\n", + "marked_states_2 = [2, 5]\n", + "N_2 = 2**n_search\n", "\n", - "counting_qubits = list(range(n_counting))\n", - "search_qubits = list(range(n_counting, n_counting + n_search))\n", + "counting_qubits_2 = list(range(n_counting))\n", + "search_qubits_2 = list(range(n_counting, n_counting + n_search))\n", "\n", - "grover = build_grover_matrix(n_search, marked_states)\n", - "circ = Circuit()\n", - "circ = quantum_counting_circuit(circ, counting_qubits, search_qubits, grover)\n", + "circ_2 = Circuit()\n", + "circ_2 = quantum_counting_circuit(\n", + " circ_2, counting_qubits_2, search_qubits_2, marked_states_2\n", + ")\n", "\n", "device = LocalSimulator()\n", - "task = run_quantum_counting(circ, device, shots=2000)\n", + "task_2 = device.run(circ_2, shots=2000)\n", "\n", - "print(\"Quantum Counting Results (N=8, M=2):\")\n", - "results = get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True)\n", + "print(f\"Quantum Counting Results (N={N_2}, M={len(marked_states_2)}):\")\n", + "results_2 = get_quantum_counting_results(\n", + " task_2, counting_qubits_2, search_qubits_2, verbose=True\n", + ")\n", "\n", - "print(f\"\\nActual M = {len(marked_states)}\")\n", - "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")" + "print(f\"\\nActual M = {len(marked_states_2)}\")\n", + "print(f\"Estimated M = {results_2['best_estimate']:.4f}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "histogram2", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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X3311apQoYLmzp2bqvVPmDBB5cuX15NPPqlXXnlFZcuW1YMPPqhx48YlW3bbtm268cYb1bZtW73yyisqWrSo7rzzTm3YsMEpy4ABAyRJTz75pHMaco0aNVJVtv79+2vr1q0aMWKErr/+er311lsaOnSoOnfurISEBD3//PNq0aKFXn75ZU2fPv286/rhhx906NAh3XbbbcqdO/cFY+/fv19XXnml5s+frwcffFDPPfecTp06peuvv16ffvppquojSYcPH9a1116runXr6pVXXlH16tU1ePBgffXVV5KkGjVqaOTIkZKke++912nDq6+++rzrnTlzpl5++WXdd999GjVqlHbu3KkbbrhBp0+fdpb54osvdMsttyhv3rwaPXq0brjhBvXu3VurV69OdX2k/yXGSZPA5557Tj179tQVV1yhV199VQMHDtTixYt19dVX68iRI5LOJHPt27fXihUr1L9/f40bN0733nuvtm/f7iyTFmPHjlWZMmVUvXp1px2feuopSWd+gBoxYoRat26tN998U0899ZTKlSunNWvWnHedq1evVlxcnBo0aHDOZZ566inFx8frhRdeOO+6Tp8+rb///vui/pJeM9+qVSvFxMTovvvu06ZNm7Rr1y5NnDhRs2fP1pAhQy6hhZKrUKGCIiMj9f777zvTvvrqKx09elTdu3dP8T2HDx++qDqcPHnygvGjo6NVoEABFShQIGB6aGioKleurB9//DFN9QMAT3l9qB0AkNyRI0dMknXp0uW8y11//fUmyWJiYszMrFevXla+fPlkyz3zzDN29i7/5MmTyZZr3769VapUKWBa+fLlTZJ99913zrQDBw5YUFCQPfLII860851eLsmeeeaZZNPLly9vvXr1cl77T3Vt3759wGngkZGR5vP57P7773emxcfHW5kyZS54CvF//vMfk2SffvrpeZfzGzhwoEmy77//3pl27Ngxq1ixolWoUMESEhICypr0lGaz/51OnLQdWrZsaZJs2rRpzrTY2FgLDw+3bt26OdPOd3r52dt2x44dJsmKFy9uhw4dcqZ/9tlnJsnmzp3rTKtdu7aVKVPGjh075kxbsmSJSUqxv5ytZcuWVr16dTt48KAdPHjQNm/ebI899phJCjjleOfOnZY7d2577rnnAt6/bt06y5MnjzP9l19+ueAp1/76pdQWZ/enSzm9vG7duqk6TXry5MkmydatW5dsXtJTr++66y4LDg62vXv3mlnKp5f7p13MX9I6xcfHW79+/Sxv3rzO/Ny5c9uECRMuuT5+/rZbtWqVvfnmm1a4cGFn33DTTTdZ69atk9Uxab0vpg4pjf2ktm7dasHBwXbHHXekOL9du3ZWo0aNVNcRALyWx5VMHgCQJv5TLAsXLnze5fzzjx07dsFlz5b0dNSjR4/q9OnTatmypebPn6+jR48qNDTUmR8RERFwxP2yyy5TtWrVtH379kuKebF69+4dcBp406ZNtXz5cvXu3duZljt3bjVq1OiCR2tjYmIkXbgt/b788ks1adJELVq0cKYVKlRI9957r4YMGaKNGzeqVq1al1IdZx09evRwXufLl09NmjRJcxvecsstKlq0qPPav5386927d6/WrVunJ598MuCO2y1btlTt2rWd9rmQzZs3J7vM4frrr9fbb7/tvJ49e7YSExN188036++//3amh4eH64orrtC3336rJ5980ulb8+fP13XXXZfs6KabihQpog0bNmjr1q264oorLvp9//zzjyQFtHVKnn76aU2fPl0vvPCC/vOf/6S4TN26dS94OrtfeHi48//cuXOrcuXKat++vW666SYFBwfr/fffV//+/RUeHq6uXbteXGXO4eabb9bAgQM1b948XXvttZo3b55ef/31cy7/3nvv6d9//73geitVqnTOeSdPntRNN92k/Pnzn/MMgaJFi+qXX365cAUAIJMi6QaATChpMn0+x44dk8/nS3aN5MX48ccf9cwzz2j58uXJTv88O+kuV65csvcXLVpUhw8fvuS4F+PseP6ylC1bNtn0C5UhJCRE0oXb0m/Xrl0pPhvYf6r8rl27UpV0lylTJtn15EWLFtVvv/12yetK6uy28ieF/nbZtWuXJKlKlSrJ3lulSpULnlbtV6FCBU2aNEmJiYn6448/9Nxzz+ngwYMKDg52ltm6davM7JzJbN68eSVJFStW1KBBg/Tqq6/qvffe01VXXaXrr79ePXr0COh3bhg5cqS6dOmiqlWrqlatWrr22mt1xx13qE6dOhf1frvAPQQqVaqkO+64Q2+99ZaeeOKJFJcpWrToOa8NPx9/Ir9161bnB5Sbb75ZrVu3Vt++fdWpUyflyZP6r3aXXXaZoqKiNHPmTJ08eVIJCQm68cYbz7l88+bNUx1LOvMItu7du2vjxo366quvVLp06RSXM7MU78UAAFkFSTcAZEKhoaEqXbr0BROy3377TWXKlFG+fPkk6ZxfTM9+hu8ff/yha665RtWrV9err76qsmXLKl++fPryyy/12muvJXv28rmuhb5QAnIh53q28LnipTT9QmWoXr26JGndunVpPhKY1MW2tZ9bbejWes9WsGDBgESxefPmatCggZ588knnaGhiYqJ8Pp+++uqrFMuV9Ej7K6+8ojvvvFOfffaZFixYoAEDBmj06NFasWJFij9Q+KX2edR+V199tf744w8n7uTJk/Xaa69p4sSJ6tOnzznfV7x4cUlnfswoU6bMeWM89dRTmj59ul588cUU+1xcXJwOHTp0UeW97LLLnLYcP3682rRpE9CO0pkzDgYNGqSdO3em+OPKpbjtttt0zz33KDo6Wh06dEh207akDh48eFHbo1ChQsnKLEn33HOP5s2bp/fee09t2rQ55/sPHz6cqh8WASCz4EZqAJBJde7cWTt27NAPP/yQ4vzvv/9eO3fudO4aLp05gpbSjaj8Rzv95s6dq9jYWH3++ee67777dN111ykqKipNd0A+35GolMoVFxenffv2pTrexWrRooWKFi2q999//6IShPLly6f4POzNmzc786X/HVE+u15nt/WlcONonr+827ZtSzYvpWkXq06dOurRo4f++9//avfu3ZKkypUry8xUsWJFRUVFJftr1qxZwDpq166tp59+Wt99952+//57/fXXX5o4caKktLfv+dqyWLFiuuuuu/T+++9rz549qlOnznnvhi7978ebHTt2XDB25cqVnbZJqY8vW7ZMpUqVuqi/pHd9379/f4p92H/TvPj4+AuW7UL+7//+T7ly5dKKFSsueNfyxo0bX1QdUnrO9mOPPaYpU6botdde06233nreODt27Ej1TRkBIDMg6QaATOrRRx9VgQIFdN999znXk/odOnRI999/v0JCQtSvXz9neuXKlXX06NGAI+T79u1Ldtdt/5GzpEdDjx49qilTpqS6vAULFpSUPEnyl+u7774LmPbWW2+l+ajlxShQoIAGDx6sTZs2afDgwSkeAZ4xY4Z++uknSdJ1112nn376ScuXL3fmnzhxQm+99ZYqVKigiIgISWfqJCmgXgkJCXrrrbdSXdbztWFqlS5dWrVq1dK0adN0/PhxZ/rSpUu1bt26NK378ccf1+nTp/Xqq69Kkm644Qblzp1bI0aMSNbOZub045iYmGQJYu3atZUrVy7FxsZKOnNZQIkSJZL1m/Hjx19U2QoWLJhiO549lgoVKqQqVao4cc+lYcOGypcvn37++eeLiv/000/r9OnTAY+F8/Nf030xf0mv6a5ataoWLlwYUIeEhAR9+OGHKly4sNMn06JQoUKaMGGChg8frs6dO5932ffee++i6tCzZ8+A97388ssaM2aMnnzyST300EPnjXH06FH98ccfuvLKK9NcNwDwCqeXA0AmVaVKFU2bNk233nqrateurd69e6tixYrauXOn3n77bR0+fFizZs1SxYoVnfd0795dgwcP1v/93/9pwIABOnnypCZMmKCqVasGXLvbrl075cuXT507d9Z9992n48ePa9KkSSpZsmSqjz7Xq1dPuXPn1osvvqijR48qKCjIeQ54nz59dP/996tbt25q27atfv31V82fPz/DThl97LHHtGHDBr3yyiv69ttvdeONNyo8PFzR0dGaM2eOfvrpJy1btkyS9MQTT+j9999Xhw4dNGDAABUrVkzvvvuuduzYoU8++US5cp35vbpmzZpq1qyZhgwZokOHDqlYsWKaNWtWmo42Vq5cWUWKFNHEiRNVuHBhFSxYUE2bNg3Yxqnx/PPPq0uXLmrevLnuuusuHT58WG+++aZq1aoVkIhfqoiICF133XWaPHmyhg4dqsqVK2vUqFEaMmSIdu7cqa5du6pw4cLasWOHPv30U91777169NFH9c0336hfv3666aabVLVqVcXHx2v69OnKnTu3unXr5qy/T58+euGFF9SnTx81atRI3333nX7//feLKlvDhg01YcIEjRo1SlWqVFHJkiXVpk0bRUREqFWrVmrYsKGKFSumn3/+WR9//HHAj1cpCQ4OVrt27bRo0SLn0W7n4z/a/e677yabl9prup944gn16NFDTZs21b333qv8+fPr/fff1+rVqzVq1CjnmnnpzHPd/f32Up/F3qtXr4taLjXXdH/66ad6/PHHdcUVV6hGjRqaMWNGwPy2bdsqLCzMeb1o0SKZmbp06XLJsQAg0/DknukAgIu2bt06u+222yw8PNxy5cplkiw4ONg2bNiQ4vILFiywWrVqWb58+axatWo2Y8aMFB8Z9vnnn1udOnUsODjYKlSoYC+++KK98847yR5T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liypxx57TPHx8RlcegAAAAAAkssUSfeqVav03//+V3Xq1AmY/vDDD2vu3Ln66KOPtHTpUu3du1c33HCDMz8hIUEdO3ZUXFycli1bpnfffVdTp07VsGHDMroKAAAAAAAkk6qke82aNVq3bp3z+rPPPlPXrl315JNPKi4u7pLWdfz4cd1+++2aNGmSihYt6kw/evSo3n77bb366qtq06aNGjZsqClTpmjZsmVasWKFJGnBggXauHGjZsyYoXr16qlDhw569tlnNW7cuEsuBwAAAAAA6S1VSfd9992n33//XZK0fft2de/eXQUKFNBHH32kxx9//JLW1bdvX3Xs2FFRUVEB01evXq3Tp08HTK9evbrKlSun5cuXS5KWL1+u2rVrKywszFmmffv2iomJ0YYNG84ZMzY2VjExMQF/AAAAAACkt1Ql3b///rvq1asnSfroo4909dVXa+bMmZo6dao++eSTi17PrFmztGbNGo0ePTrZvOjoaOXLl09FihQJmB4WFqbo6GhnmaQJt3++f965jB49WqGhoc5f2bJlL7rMAAAAAABcrFQl3WamxMRESdKiRYt03XXXSZLKli2rv//++6LWsWfPHj300EN67733FBwcnJpipNqQIUN09OhR52/Pnj0ZGh8AAAAAkDOkKulu1KiRRo0apenTp2vp0qXq2LGjJGnHjh3Jjjyfy+rVq3XgwAE1aNBAefLkUZ48ebR06VK9/vrrypMnj8LCwhQXF6cjR44EvG///v0KDw+XJIWHhye7m7n/tX+ZlAQFBSkkJCTgDwAAAACA9JaqpPu1117TmjVr1K9fPz311FOqUqWKJOnjjz/WlVdeeVHruOaaa7Ru3TqtXbvW+WvUqJFuv/125/958+bV4sWLnfds2bJFu3fvVmRkpCQpMjJS69at04EDB5xlFi5cqJCQEEVERKSmagAAAAAApJs8qXlT3bp1A+5e7vfyyy8rT56LW2XhwoVVq1atgGkFCxZU8eLFnem9e/fWoEGDVKxYMYWEhKh///6KjIxUs2bNJEnt2rVTRESE7rjjDr300kuKjo7W008/rb59+yooKCg1VQMAAAAAIN2k6kh3pUqV9M8//ySbfurUKVWtWjXNhfJ77bXX1KlTJ3Xr1k1XX321wsPDNXv2bGd+7ty5NW/ePOXOnVuRkZHq0aOHevbsqZEjR6ZbGQAAAAAASK1UHeneuXOnEhISkk2PjY3Vn3/+merCLFmyJOB1cHCwxo0bp3Hjxp3zPeXLl9eXX36Z6pgAAAAAALjlkpLuzz//3Pn//PnzFRoa6rxOSEjQ4sWLVbFixfQrHQAAAAAAWdglJd1du3aVJPl8PvXq1StgXt68eVWhQgW98sor6VY4AAAAAACysktKuv3P5q5YsaJWrVqlEiVKuFIoAAAAAACyg1Rd071jx470LgcAAAAAANlOqpJuSVq8eLEWL16sAwcOOEfA/d555500FwwAAAAAgKwuVUn3iBEjNHLkSDVq1EilSpWSz+dL73IBAAAAAJDlpSrpnjhxoqZOnao77rgjvcsDAAAAAEC2kSs1b4qLi9OVV16Z3mUBAAAAACBbSVXS3adPH82cOTO9ywIAAAAAQLaSqtPLT506pbfeekuLFi1SnTp1lDdv3oD5r776aroUDgAAAACArCxVSfdvv/2mevXqSZLWr18fMI+bqgEAAAAAcEaqku5vv/02vcsBAAAAAEC2k6prugEAAAAAwIWl6kh369atz3sa+TfffJPqAgEAAAAAkF2kKun2X8/td/r0aa1du1br169Xr1690qNcAAAAAABkealKul977bUUpw8fPlzHjx9PU4EAAAAAAMgu0vWa7h49euidd95Jz1UCAAAAAJBlpWvSvXz5cgUHB6fnKgEAAAAAyLJSdXr5DTfcEPDazLRv3z79/PPPGjp0aLoUDAAAAACArC5VSXdoaGjA61y5cqlatWoaOXKk2rVrly4FAwAAAAAgq0tV0j1lypT0LgcAAAAAANlOqpJuv9WrV2vTpk2SpJo1a6p+/frpUigAAAAAALKDVCXdBw4cUPfu3bVkyRIVKVJEknTkyBG1bt1as2bN0mWXXZaeZQQAAAAAIEtK1d3L+/fvr2PHjmnDhg06dOiQDh06pPXr1ysmJkYDBgxI7zICAAAAAJAlpepI99dff61FixapRo0azrSIiAiNGzeOG6kBAAAAAPD/pepId2JiovLmzZtset68eZWYmJjmQgEAAAAAkB2kKulu06aNHnroIe3du9eZ9tdff+nhhx/WNddck26FAwAAAAAgK0tV0v3mm28qJiZGFSpUUOXKlVW5cmVVrFhRMTExeuONN9K7jAAAAAAAZEmpuqa7bNmyWrNmjRYtWqTNmzdLkmrUqKGoqKh0LRwAAAAAAFnZJR3p/uabbxQREaGYmBj5fD61bdtW/fv3V//+/dW4cWPVrFlT33//vVtlBQAAAAAgS7mkpHvs2LG65557FBISkmxeaGio7rvvPr366qvpVjgAAAAAALKyS0q6f/31V1177bXnnN+uXTutXr06zYUCAAAAACA7uKSke//+/Sk+KswvT548OnjwYJoLBQAAAABAdnBJSffll1+u9evXn3P+b7/9plKlSqW5UAAAAAAAZAeXlHRfd911Gjp0qE6dOpVs3r///qtnnnlGnTp1SrfCAQAAAACQlV3SI8OefvppzZ49W1WrVlW/fv1UrVo1SdLmzZs1btw4JSQk6KmnnnKloAAAAAAAZDWXlHSHhYVp2bJleuCBBzRkyBCZmSTJ5/Opffv2GjdunMLCwlwpKAAAAAAAWc0lJd2SVL58eX355Zc6fPiwtm3bJjPTFVdcoaJFi7pRPgAAAAAAsqxLTrr9ihYtqsaNG6dnWQAAAAAAyFYu6UZq6W3ChAmqU6eOQkJCFBISosjISH311VfO/FOnTqlv374qXry4ChUqpG7dumn//v0B69i9e7c6duyoAgUKqGTJknrssccUHx+f0VUBAAAAACAZT5PuMmXK6IUXXtDq1av1888/q02bNurSpYs2bNggSXr44Yc1d+5cffTRR1q6dKn27t2rG264wXl/QkKCOnbsqLi4OC1btkzvvvuupk6dqmHDhnlVJQAAAAAAHKk+vTw9dO7cOeD1c889pwkTJmjFihUqU6aM3n77bc2cOVNt2rSRJE2ZMkU1atTQihUr1KxZMy1YsEAbN27UokWLFBYWpnr16unZZ5/V4MGDNXz4cOXLl8+LagEAAAAAIMnjI91JJSQkaNasWTpx4oQiIyO1evVqnT59WlFRUc4y1atXV7ly5bR8+XJJ0vLly1W7du2AO6a3b99eMTExztFyAAAAAAC84umRbklat26dIiMjderUKRUqVEiffvqpIiIitHbtWuXLl09FihQJWD4sLEzR0dGSpOjo6GSPKPO/9i+TktjYWMXGxjqvY2Ji0qk2AAAAAAD8j+dHuqtVq6a1a9dq5cqVeuCBB9SrVy9t3LjR1ZijR49WaGio81e2bFlX4wEAAAAAcibPk+58+fKpSpUqatiwoUaPHq26devqP//5j8LDwxUXF6cjR44ELL9//36Fh4dLksLDw5Pdzdz/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FCmiOnXq6O2339bTTz+t8ePHS5Ly5Mmj+Pj4dI357rvv6tZbb9Xhw4eVL18+DRw4UE888YRmz54t6Uyd/c++/OGHH9S6dWtVr15dZkbM83jvvffUoEEDDRs2THv27HFipGTFihUqV66c6tSpI0mpfjSHF+06bdo0VapUSa+//roz7VzjJL1iejE2c0o9vYg5ZcoU3XTTTVqzZo02bdqkzp07a/DgwVq+fLmkM+PB32+/++473XDDDapataoSExOzzNjMCe0qebMP8mJ7etG2GR1z+vTpuvzyy53HGvl8vmTt5e+z6VVHL74DebFv9yJmThmbs2bNUp8+fVSvXj3deOONWr9+vYYPH66hQ4dKCuxD6RFz1qxZatGihV544QUtW7ZM0pk6+rdfUj///LMKFSqkevXqpTqeZzIyw4d3li1bZlWrVrVu3bpZ/vz57dFHH0122pFfTEyM1apVy8aNG5flYsbExFiHDh0CHnvx66+/Wt++fa1GjRo2duxYZ/qRI0fSJeaBAwesWbNm9tZbbznTli5dap06dbKrrrrKuTmKf9nixYvb5MmTiXkBP/30k9WsWdP69OljhQsXtltvvdV2796d4rKnTp2yqKgoe+WVV1Idz8ybdv3uu++sUqVK1qZNG8uXL19AHz3bwYMH0yWmF2Mzp9TTi5i7d++2WrVq2bRp05xpn332mdWqVctuuOGGgKMHe/bsMZ/PZzNmzEh1PC/GZk5oVzNv9kFebE8v2jajY37zzTdWtmxZa9SokRUrVszee+89Z15Kp5qnRx29+A7kxb7di5g5ZWzGxsbarbfeakOHDnWm7dy501588UW77LLL7IknnnCmnzhxIs0x16xZY3Xr1rX77rvPatasaZ07d7Yff/zRmX/2qeZ33HGHPffcc6mO5yWS7hwgLi7O3nnnHevTp4/99ddf9sknn1jevHnP+6Vl3rx5zikbqTklxouYZmb//vuvVatWLWBnYWb2xx9/2IABA6xx48YBNy354osv0hwzJibGKlSoYOPHjw+Yvnr1auvatat16NDBOb3IzAJ2zMRMWXx8vM2dO9f69OljR48etZ9//tmCg4PP+4GzdOlS53SkrFBHszP99cUXX7R77rnHNm/ebK+88or5fL6ALxBnr/f9999PU0wvxmZOqadX+73o6GgrV66cc7qd3zfffGP169e3Hj162J49e5zpb7/9tvP/rDA2c0K7+mX0Psirfa0XbZuRMY8fP26PPPKI3X///bZy5Up75JFHrHDhwudNvJMmaFnlO5AX+3YvYppl/NhMSEjwZGzGxcVZgwYN7J577gmY/vfff9srr7xiFStWtP/+97/O9O+//z5NMZcvX+7s2zdu3GjVq1dPlngn9csvvzint2eV53P7kXTnENu3b7fVq1c7rz/88EPnS0tsbKwz/d9//82yMRMTEy02NtZ69uxpvXr1SnbDkPXr11vLli2T7UjSGvOff/6xFi1a2JNPPmlmgdehLFu2zCpVqmTDhg1Lt5gJCQk5IuaBAwecO36ama1YscL5wNm1a5cz/cSJE+kSz4s6mp3pl/4Pl9jYWHv55ZeTfYHwz0svXuwPcko9vdjv7dy50ypVqmQTJkwwszNt6P8y8vXXX1uhQoUCviSlVUaPTTNvtuWuXbsytF29+Dwxy/jt6UWf9SLmTz/9ZN98842ZnTmS/fDDDydLvM0Cr49NCy++A/nXm9H79oyO6dXYjI6OzvB9rZnZ0KFDrV27dgHXq5uZ/fnnn3bnnXda165d0+2GhsePHw+4Nv/XX391Eu8ffvjBme7Wjf4yEkl3NpfSr0D+XzU/+ugjy5s3rz322GMWHx9v+/fvtxEjRtivv/6a7uVwO2bSevq/jI0fPz7ZDRamTp1q+fPnt7/++itN8c42YcIEy5MnT8DjC/xlevnlly0sLMyOHDmSrr/KvfHGG9kyZko3xfAfzVq5cqXzgfPnn3/agQMHrF+/fgGPP0krL9o1qX///dfGjBkT8AUiOjraxo8ff85ft9PCi/2Bmbv1zCn7vaSGDh1qwcHBzjrj4uKc+IMGDbI6derYyZMn03TTGS/Gptfbcvjw4a6369ky6vPE631tRvTZzBDTb/fu3TZo0CArXLiwzZw508zO7PM+/vjjNN/d2uvvQEll9L7d7ZhJefFdz7+ujNzXLlq0yMqUKWNPPvlksjvBf/bZZ5YrV65kCfmlSmmM+X+A+u2335zEe9myZXbw4EG75ZZbkp2lktWQdGdT//zzz0WdMvTRRx9Zvnz5rF+/fta4cWOrWbPmOe8YeCHffPONTZgwwcaMGWM//fSTM/3sX3HTM+aePXucRyYkHcCjRo2yvHnz2qRJkwI+zObPn2+NGjWyf/75J1XxzALbNmnMBx54wAoUKGALFiwIWP7dd9+15s2bp/hoh4uVtG1XrlzpbNM+ffpkm5hJt2VKfdbfR3766ScrUKCAdevWzerWrWsRERHp0mczql1//PFH+/jjj23atGn2559/OtOTjpOTJ0/amDFjLHfu3DZq1Chr3ry51a5dO9VfBL0Ym17UM6fs95K2rf8LZWxsrHXq1MlKlChh69evD1j+hRdesKioqFTFMvNmbHqxLZMeJffHPnTokHXt2tWVdjXz5vPEi+2Z0X3Wi5irV6+2b7/91r744ouA7ZN0X7Br1y4bNGiQhYaG2sSJE61FixZWp06dVCdpXnwH8mLffjFnsLj5eZJRY/Orr76yESNG2OOPP26ffPKJ0y/8486Nsbl582anjyRdx1tvvWW5cuWyoUOHOs+NNztzDXb9+vVt+/btaY6X0rbxT1u3bp1FRERYhw4drFq1alajRo10OyvEKyTd2dD06dPtqquusmXLll3Ujnzy5Mnm8/mscePGzi9pl7qTevvtt61QoULWrl07K1asmNWtW9fuvPNOZz1nD5T0iDljxgyrVauWzZgxwzmFKOkOY9iwYebz+eyxxx6zuXPn2u+//27t2rWza665JtUfcCm1rf/ff/75x/r06WP58uWzN954w1auXGn79u2ztm3bWufOnVMdM6W27dWrl9NevXr1yvIxU9qW5zvC9fXXX5vP57OmTZs6/edSP3C8aNfJkydbSEiINW3a1PLmzWuNGze24cOHO+tLOk5iY2NtxIgR5vP5rFGjRk49LzW2F2PTi3rmlP3e2W3bqFEjGzFihJmdOZJ27bXXWkhIiH3++ee2fft2O3r0qEVFRdmtt956SXH8vBibXmzLadOmWZcuXQIe7+S3bt0669y5c7q2q5k3nydebM+M7rNexJw0aZIVL17catasaT6fz1q1amVTpkxx5ifdF/z555/2wAMPmM/ns4YNG6Z6n+fFdyAv9u3nG5tnc/PzxO2xOWXKFMufP7/dcsstVq1aNatZs6a1bt3a+cHBv23Tc2zOmDHDLr/8cnv22Wed07eTbsMJEyZY0aJF7fbbb7fJkyfbihUrrG3btta8efNU/ZiRUrzz7X+WLFmS5jpmJiTd2cxXX31lJUuWtODgYGvQoIH99NNP590BHDhwwJo0aWL169d3Btql/pK0fft2q1ixok2dOtXMzlyf8Z///Mfq1Klj11xzjTN4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yBHnS33SR/+YnWn78uXLW5s2bWzdunXWrFkzu/3221Md04t6Ju2z/iODZyf9bn1uZuT+IGnb+sv9888/W1BQkD344IPpHjNp//GPmdmzZzt3zfbzt3WnTp3SnOR7PTYzol3NvBmbXnyeHD161Pm/fx07d+60Zs2aWbt27ZLdGf21116zq6++Ok3Pxk4a82xJz7zo27evNWnSxIYOHWqRkZFWuXLlVH2OZXS8rICkOwubPHmylS1b1kqXLm0VKlSwa665xn777TczC/yFzuxMB/ffVbNmzZqpvtnDJ598Yn369LEtW7Y40/w7pbVr11qRIkWsc+fO9vnnn1t8fLwdPnzYrrrqKnvggQdSXc+UYp4t6VGD9u3bm8/nszp16qS6njm5bd2M6cW2nDRpkoWHh1vFihWtfPnyVqVKFVu4cKFrdTRL3n/atGlja9asMTOzOXPmWL58+axHjx7266+/WmJiop08edKaNGligwcPTnVML/qPF/X0YmzmhD7kxdj87LPP7LnnnjvvzZHSe1u+8847VqVKFQsPD7fKlSvbPffcY7///rsTI+k6t23bZhUqVDCfz2fVq1cPuMbxUnhRz5T67NlH6t3+3MyI/UFKbevfjnPnzrWgoKB0jZm0/1SpUiVgzIwdO9Zy5cplgwcPtr///tvMziRr9evXt+effz7VdcwsY9PNdjXzZmx68XnywQcf2DXXXOMcNfcf6TY78yN5gwYNLCoqyt544w2LjY21ffv22TXXXGN33HFHquqYUsyUJG3j3r17m8/nswYNGqTqpmkZHS+rIOnOor777jsrVKiQTZ8+3bZv324zZ860zp07W6FChQKu8zE703FjY2OtefPmduWVV6b6LoCfffaZ5c6d2y6//HIbMGCAbd261czODBj/utavX28tWrSwWrVq2eWXX24NGza02rVrp+nLSkoxU5KQkGAnT560Fi1aWLNmzVJdz5zetm7F9GJbrly50ooUKWKzZs2ygwcP2g8//GB33nmn5c6d29555x0zM/vtt9+sefPm6dau5+o/BQsWdK4TW7JkiROrVq1aFhkZaTVr1kz1dUte9B8v6unF2MwJfciLsTl79mzz+XxWvHhxGzNmjHOq6Llipse2XLhwoRUsWNAmTZpka9eutdGjR9s111xj1apVc75oJz3CcvjwYatXr541b948S9XzXH02T548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04uYXrTtuWKe6xfCrNi2XmxL/zWMl112mb322mvO9KTb8tlnn7WmTZtaWFiY3XLLLdaoUaM03W01p/efm266yfkif++991q9evVc3we5GTMn9CEv+s/HH39swcHB9uabb9pLL71kffv2tdy5c9ujjz4a8KXdHzM2NtaKFy+epjsEnyvmQw895CwTFRVltWrVsi5dutioUaOsVatWVqdOnTRdN5nR9fSiz3oxNjO6bb3oP4zNh5xl0rttM9PnybmS0mPHjlmlSpWsadOm6b4/cCumF3XM6ki6M7FffvnFGjVqZPfcc4/deuut1rx5c5sxY4YzP+kH69y5c23AgAF266232sMPP5zqu2Wanbn7Zbdu3QKmLV++3AoXLmw33nijc71PYmKiHT9+3Bo0aGAVKlRI0yDK6JhetO2FYp69o8qqbZvR8fyPwurbt689+uijVq1aNRszZowzP+m2XLt2rT377LPWv39/Gz58uGvbMqf0n65duzr1mDNnTobsg9yImRP6kFf957777rN77rnHef3vv//a+++/b/nz5w/4op2YmGhHjx61Ro0aWcWKFV2LmfSU2Ndff926d+9u1157rfXp0yfgebzpGdONenrRZ8282R9kdNtmdP9hbLo7NjPb58nZ2/PkyZPWoUMHu+KKK1J9B++MjulFHbMDku5M7Pfff7fu3bvbpk2bbP369XbrrbdaixYtAnbG5zu951I7tP/XqB49eliHDh2Sxfj555+tYMGCNnjw4ID3ffDBB6keRF7ENMv4tr3YmGefTpaV2tarbfnXX3/ZXXfdZb/88ov9+eefNnjw4GQfAF5sy5zSf853bWhWiGmWM/pQRvcfszNfVqOioqxHjx7JYnz88ceWO3fugCMkZmdOm3U75tmnVidt56xSz4zus16NzYxuWy/6D2PTnbbNzJ8nZyelX3zxhev7g/SM6UUdswOS7kzGv5Pw/+u/U6TZmV9DU9oZHz9+PF3L8PHHH1tQUFDAXRv9A2T69OlWrFgx5/mFSaVlEGVETC/aNjUxk97Mwy+zt61X8fzt6j9FzOzM3XlT+gA4evRosi8uqYlF/0m+Pc/3KJDMHjM79yEv+s/Z7TN+/HgrVaqU8wgiv4SEBHvuuecsIiIi2V1sMyJmSncHvpRt60U9z46dEX32bBkxNjO6bb3sP4zN5DHT2rZny6yfJzExMcnq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zjslSYmJiRo9erQqVqyo/Pnzq27duvr444+dMvhjfPXVV2rYsKGCgoL0ww8/nLPevXr10qxZs/Tvv/8609555x316tUr2bJ79uzRzTffrCJFiqhYsWLq0qWLdu7c6cxftWqV2rZtqxIlSig0NFQtW7bUmjVrnPlmpuHDh6tcuXIKCgpS6dKlNWDAAGd+Smc7FClSRFOnTpV05ocin8+nDz74QC1btlRwcLDee++9C24b//s+/PBDXXXVVcqfP78aN26s33//XatWrVKjRo1UqFAhdejQQQcPHgyIfzHrnT17tlq3bq0CBQqobt26Wr58ubMt7rrrLh09etQ5qyBpvwcAeMQAAHDZP//8Yz6fz55//vnzLpeQkGD16tWzFi1a2M8//2wrVqywhg0bWsuWLZ1levXqZV26dAl430MPPRSwTMuWLS0kJMSGDx9uv//+u7377rvm8/lswYIFZmZ24MABk2RTpkyxffv22YEDB8zM7JlnnrG6desGxAoJCbH777/fNm3aZHPnzrUCBQrYW2+95SwTFRVl9erVsxUrVtjq1autZcuWlj9/fnvttdfOWc+z4+zYscNq1qxpYWFhzrQZM2ZYqVKl7JNPPrHt27fbJ598YsWKFbOpU6eamdnRo0etWLFi1qNHD9uwYYN9+eWXVrVqVZNkv/zyi5mZffvttybJDh8+bGZmHTt2tLZt29pvv/1mf/zxh82dO9eWLl1q8fHx9sknn5gk27Jli+3bt8+OHDliZmajRo2y6tWr29dff21//PGHTZkyxYKCgmzJkiUBMerUqWMLFiywbdu22T///JNivSXZp59+anXq1LHp06ebmdmuXbssKCjIfv/9d5Nk3377rZmZxcXFWY0aNezuu++23377zTZu3Gi33XabVatWzWJjY83MbPHixTZ9+nTbtGmTbdy40Xr37m1hYWEWExNjZmYfffSRhYSE2Jdffmm7du2ylStXBmw7f3mSCg0NtSlTpjjbRZJVqFDB2Q579+694Lbxv8/fbhs3brRmzZpZw4YNrVWrVvbDDz/YmjVrrEqVKnb//fdf9DZPut558+bZli1b7MYbb7Ty5cvb6dOnLTY21saOHWshISG2b98+27dvnx07duyc/RAAkDFIugEArlu5cqVJstmzZ593uQULFlju3Llt9+7dzrQNGzaYJPvpp5/M7OKT7hYtWgQs07hxYxs8eLDzOqWEK6Wku3z58hYfH+9Mu+mmm+yWW24xM7NNmzaZJFu1apUzf+vWrSbpgkl3rly5rGDBghYcHGySTJK9+uqrzjKVK1e2mTNnBrzv2WeftcjISDMzmzBhghUvXtz+/fdfZ/6kSZPOm3TXrl3bhg8fnmKZzl7WzOzUqVNWoEABW7ZsWcCyvXv3tltvvTXgfXPmzDlnff38bT527Fhr3bq1mZmNGDHC/u///s8OHz4ckHRPnz7dqlWrZomJic77Y2NjLX/+/DZ//vwU15+QkGCFCxe2uXPnmpnZK6+8YlWrVrW4uLjzlieplJLusWPHBixzoW3jf9/kyZOd+e+//75JssWLFzvTRo8ebdWqVUvTev3jY9OmTWZmNmXKFAsNDU2xvgAAb3BNNwDAdWZ2Uctt2rRJZcuWVdmyZZ1pERERKlKkiDZt2qTGjRtfdMw6deoEvC5VqpQOHDhw0e/3q1mzpnLnzh2wnnXr1kmStmzZojx58qhBgwbO/CpVqqho0aIXXG+1atX0+eef69SpU5oxY4bWrl2r/v37S5JOnDihP/74Q71799Y999zjvCc+Pt65KdqWLVtUp04dBQcHO/ObNGly3pgDBgzQAw88oAULFigqKkrdunVL1k5Jbdu2TSdPnlTbtm0DpsfFxal+/foB0xo1anTBOvv16NFDTzzxhLZv366pU6fq9ddfT7bMr7/+qm3btqlw4cIB00+dOqU//vhDkrR//349/fTTWrJkiQ4cOKCEhASdPHlSu3fvliTddNNNGjt2rCpVqqRrr71W1113nTp37nzO683PJWndLmbb+CVt27CwMElS7dq1A6b5+2Rq11uqVClJ0oEDB1S9evVLqhcAIGOQdAMAXHfFFVfI5/Oly83ScuXKlSyJT3qNtd/ZN7vy+XxKTEy85HjptZ6z5cuXT1WqVJEkvfDCC+rYsaNGjBihZ599VsePH5ckTZo0SU2bNg14X9IfAC5Vnz591L59e33xxRdasGCBRo8erVdeecVJ9s/mL8cXX3yhyy+/PGBeUFBQwOuCBQtedDmKFy+uTp06qXfv3jp16pQ6dOigY8eOJYvdsGFD5xrqpC677DJJZ64P/+eff/Sf//xH5cuXV1BQkCIjIxUXFyfpzE3btmzZokWLFmnhwoV68MEH9fLLL2vp0qXKmzevfD7fRfWlpHW7lG2TtO/4fL4Up/n7UlrXmx59EgDgDm6kBgBwXbFixdS+fXuNGzdOJ06cSDbff6OvGjVqaM+ePdqzZ48zb+PGjTpy5IgiIiIknUm49u3bF/B+/43DLkXevHmVkJBwye9Lqlq1aoqPj9cvv/ziTNu2bZsOHz58yet6+umnNWbMGO3du1dhYWEqXbq0tm/fripVqgT8VaxY0Ym9bt06xcbGOutYtWrVBeOULVtW999/v2bPnq1HHnlEkyZNknTmRwBJAW0SERGhoKAg7d69O1k5kp6NkBp33323lixZop49e6b4Q0KDBg20detWlSxZMlls/5HfH3/8UQMGDNB1112nmjVrKigoSH///XfAevLnz6/OnTvr9ddf15IlS7R8+XLnTIWz+9LWrVt18uTJ85b7YrZNaqTXevPly5fmfg0ASF8k3QCADDFu3DglJCSoSZMm+uSTT7R161Zt2rRJr7/+uiIjIyVJUVFRql27tm6//XatWbNGP/30k3r27KmWLVs6p/i2adNGP//8s6ZNm6atW7fqmWee0fr16y+5PBUqVNDixYsVHR2dqiRZkqpXr66oqCjde++9+umnn/TLL7/o3nvvVf78+Z0jkBcrMjJSderU0fPPPy9JGjFihEaPHq3XX39dv//+u9atW6cpU6bo1VdflSTddtttSkxM1L333qtNmzZp/vz5GjNmjCSdM/bAgQM1f/587dixQ2vWrNG3336rGjVqSJLKly8vn8+nefPm6eDBgzp+/LgKFy6sRx99VA8//LDeffdd/fHHH1qzZo3eeOMNvfvuu6lqM79rr71WBw8e1MiRI1Ocf/vtt6tEiRLq0qWLvv/+e+3YsUNLlizRgAED9Oeff0o6cwbF9OnTtWnTJq1cuVK333678ufP76xj6tSpevvtt7V+/Xpt375dM2bMUP78+VW+fHlJZ/rSm2++qV9++UU///yz7r///ot6HNiFtk1qpcd6K1SooOPHj2vx4sX6+++/L/gjAgDAfSTdAIAMUalSJa1Zs0atW7fWI488olq1aqlt27ZavHixJkyYIOlMsvjZZ5+paNGiuvrqqxUVFaVKlSoFPLu6ffv2Gjp0qB5//HE1btxYx44dU8+ePS+5PK+88ooWLlyosmXLJrs++VJMmzZNYWFhuvrqq/V///d/uueee1S4cOGAa60v1sMPP6zJkydrz5496tOnjyZPnqwpU6aodu3aatmypaZOneoc9QwJCdHcuXO1du1a1atXT0899ZSGDRsmSeeMnZCQoL59+6pGjRq69tprVbVqVeeRVJdffrlGjBihJ554QmFhYerXr58k6dlnn9XQoUM1evRo531ffPFFmo7qSme2dYkSJZwj7GcrUKCAvvvuO5UrV0433HCDatSo4ZyOHhISIkl6++23dfjwYTVo0EB33HGHBgwYoJIlSzrrKFKkiCZNmqTmzZurTp06WrRokebOnavixYtLOtMHypYtq6uuukq33XabHn30URUoUOCCZb/Qtkmt9FjvlVdeqfvvv1+33HKLLrvsMr300ktpKhMAIO18drF3twEAABf0559/qmzZslq0aJGuueaaDI393nvvOc9pTnrEFwAAeIcbqQEAkAbffPONjh8/rtq1a2vfvn16/PHHVaFCBV199dWux542bZoqVaqkyy+/XL/++qsGDx6sm2++mYQbAIBMhKQbAIA0OH36tJ588klt375dhQsX1pVXXqn33nvvoq4NTqvo6GgNGzZM0dHRKlWqlG666SY999xzrscFAAAXj9PLAQAAAABwCTdSAwAAAADAJSTdAAAAAAC4hKQbAAAAAACXkHQDAAAAAOASkm4AAAAAAFxC0g0AAAAAgEtIugEAAAAAcAlJNwAAAAAALiHpBgAAAADAJf8P/0rm0nK+JA4AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Visualize Example 2 results\n", + "counting_results_2 = results_2[\"counting_register_results\"]\n", + "sorted_results_2 = sorted(counting_results_2.items(), key=lambda x: x[1], reverse=True)\n", + "\n", + "labels_2 = [f\"|{bs}>\" for bs, _ in sorted_results_2]\n", + "values_2 = [c for _, c in sorted_results_2]\n", + "\n", + "plt.figure(figsize=(10, 5))\n", + "plt.bar(labels_2, values_2, color=\"steelblue\", alpha=0.8)\n", + "plt.xlabel(\"Counting Register Measurement\")\n", + "plt.ylabel(\"Counts\")\n", + "plt.title(f\"Quantum Counting Results (N={N_2}, M={len(marked_states_2)})\")\n", + "plt.xticks(rotation=45)\n", + "plt.tight_layout()\n", + "plt.show()" ] }, { "cell_type": "markdown", - "id": "ba1c59de-2601-4c7b-a9bf-481e5ea5fabf", + "id": "ba1c59de", "metadata": {}, "source": [ "## Example 3: Edge Case — No Marked Items (M = 0)\n", @@ -348,51 +480,54 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "e1f273c0-bc56-4d13-9f97-ef9f879d3d27", + "execution_count": 9, + "id": "e1f273c0", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Measurement counts: Counter({'000011': 255, '000000': 252, '000010': 249, '000001': 244})\n", - "Counting register results: {'0000': 1000}\n", - "Phase estimates: [0.0]\n", - "Estimated item counts: [np.float64(0.0)]\n", + "Search space size N = 4\n", + "\n", + "Counting register distribution (top outcomes):\n", + " |1000>: 1000 counts -> phase = 0.0000, M ~ 0.0000\n", + "\n", "Best estimate of M: 0.0\n", - "Search space size N: 4\n", "\n", "Actual M = 0\n", - "Estimated M ≈ 0.0000\n" + "Estimated M = 0.0000\n" ] } ], "source": [ "n_counting = 4\n", "n_search = 2\n", - "marked_states = []\n", - "N = 2**n_search\n", + "marked_states_3 = []\n", + "N_3 = 2**n_search\n", "\n", - "counting_qubits = list(range(n_counting))\n", - "search_qubits = list(range(n_counting, n_counting + n_search))\n", + "counting_qubits_3 = list(range(n_counting))\n", + "search_qubits_3 = list(range(n_counting, n_counting + n_search))\n", "\n", - "grover = build_grover_matrix(n_search, marked_states)\n", - "circ = Circuit()\n", - "circ = quantum_counting_circuit(circ, counting_qubits, search_qubits, grover)\n", + "circ_3 = Circuit()\n", + "circ_3 = quantum_counting_circuit(\n", + " circ_3, counting_qubits_3, search_qubits_3, marked_states_3\n", + ")\n", "\n", "device = LocalSimulator()\n", - "task = run_quantum_counting(circ, device, shots=1000)\n", + "task_3 = device.run(circ_3, shots=1000)\n", "\n", - "results = get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True)\n", + "results_3 = get_quantum_counting_results(\n", + " task_3, counting_qubits_3, search_qubits_3, verbose=True\n", + ")\n", "\n", "print(f\"\\nActual M = 0\")\n", - "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")" + "print(f\"Estimated M = {results_3['best_estimate']:.4f}\")" ] }, { "cell_type": "markdown", - "id": "c224af69-fd26-4997-bcc7-86bb1c35d4f4", + "id": "c224af69", "metadata": {}, "source": [ "## Example 4: Edge Case — All Items Marked (M = N)\n", @@ -402,62 +537,67 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "36cbb24d-a2d5-44b3-8496-42d5c6335473", + "execution_count": 10, + "id": "36cbb24d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Measurement counts: Counter({'100011': 278, '100010': 251, '100001': 243, '100000': 228})\n", - "Counting register results: {'1000': 1000}\n", - "Phase estimates: [0.5]\n", - "Estimated item counts: [np.float64(4.0)]\n", + "Search space size N = 4\n", + "\n", + "Counting register distribution (top outcomes):\n", + " |0000>: 1000 counts -> phase = 0.5000, M ~ 4.0000\n", + "\n", "Best estimate of M: 4.0\n", - "Search space size N: 4\n", "\n", "Actual M = 4\n", - "Estimated M ≈ 4.0000\n" + "Estimated M = 4.0000\n" ] } ], "source": [ "n_counting = 4\n", "n_search = 2\n", - "N = 2**n_search\n", - "marked_states = list(range(N))\n", + "N_4 = 2**n_search\n", + "marked_states_4 = list(range(N_4))\n", "\n", - "counting_qubits = list(range(n_counting))\n", - "search_qubits = list(range(n_counting, n_counting + n_search))\n", + "counting_qubits_4 = list(range(n_counting))\n", + "search_qubits_4 = list(range(n_counting, n_counting + n_search))\n", "\n", - "grover = build_grover_matrix(n_search, marked_states)\n", - "circ = Circuit()\n", - "circ = quantum_counting_circuit(circ, counting_qubits, search_qubits, grover)\n", + "circ_4 = Circuit()\n", + "circ_4 = quantum_counting_circuit(\n", + " circ_4, counting_qubits_4, search_qubits_4, marked_states_4\n", + ")\n", "\n", "device = LocalSimulator()\n", - "task = run_quantum_counting(circ, device, shots=1000)\n", + "task_4 = device.run(circ_4, shots=1000)\n", "\n", - "results = get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True)\n", + "results_4 = get_quantum_counting_results(\n", + " task_4, counting_qubits_4, search_qubits_4, verbose=True\n", + ")\n", "\n", - "print(f\"\\nActual M = {N}\")\n", - "print(f\"Estimated M ≈ {results['best_estimate']:.4f}\")" + "print(f\"\\nActual M = {N_4}\")\n", + "print(f\"Estimated M = {results_4['best_estimate']:.4f}\")" ] }, { "cell_type": "markdown", - "id": "5d747213-799b-4be7-a5b9-efc3c9bd57a6", + "id": "5d747213", "metadata": {}, "source": [ "## [Optional] Run on a QPU or Managed Simulator\n", "\n", + "**Note:** The current implementation uses `Circuit.unitary()` for the controlled-Grover operations within QPE. This gate-synthesis approach works on simulators but is **not directly compatible with QPU execution**, which requires circuits decomposed into native gate sets. To run on a QPU, the controlled-Grover operator would need to be fully decomposed into native one- and two-qubit gates.\n", + "\n", "[Include estimated price for running in USD using the [cost tracker](https://docs.aws.amazon.com/braket/latest/developerguide/braket-pricing.html#real-time-cost-tracking).]" ] }, { "cell_type": "code", - "execution_count": null, - "id": "690a8210-747e-4c22-882f-60b516a2f201", + "execution_count": 11, + "id": "690a8210", "metadata": {}, "outputs": [], "source": [ @@ -469,8 +609,8 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "2c70f923-0cce-49ab-a382-1a4c7fd296a8", + "execution_count": 12, + "id": "2c70f923", "metadata": {}, "outputs": [], "source": [ @@ -490,23 +630,24 @@ "# marked_states = [3]\n", "# counting_qubits = list(range(n_counting))\n", "# search_qubits = list(range(n_counting, n_counting + n_search))\n", - "# grover = build_grover_matrix(n_search, marked_states)\n", "\n", "# circ = Circuit()\n", - "# circ = quantum_counting_circuit(circ, counting_qubits, search_qubits, grover)\n", + "# circ = quantum_counting_circuit(\n", + "# circ, counting_qubits, search_qubits, marked_states\n", + "# )\n", "\n", - "# task = run_quantum_counting(circ, managed_device, shots=1000)\n", + "# task = managed_device.run(circ, shots=1000)\n", "\n", "# results = get_quantum_counting_results(\n", "# task, counting_qubits, search_qubits, verbose=True\n", "# )\n", - "# print(f\"\\nEstimated M ≈ {results['best_estimate']:.4f}\")" + "# print(f\"\\nEstimated M = {results['best_estimate']:.4f}\")" ] }, { "cell_type": "code", - "execution_count": null, - "id": "1c2e7121-a3d3-42c7-b334-3ba29785617b", + "execution_count": 13, + "id": "1c2e7121", "metadata": {}, "outputs": [], "source": [ @@ -519,7 +660,7 @@ }, { "cell_type": "markdown", - "id": "2ab582fd-c942-4207-a218-9d13fc73317b", + "id": "2ab582fd", "metadata": {}, "source": [ "Note: Charges shown are estimates based on your Amazon Braket simulator and quantum processing unit (QPU) task usage. Estimated charges shown may differ from your actual charges. Estimated charges do not factor in any discounts or credits, and you may experience additional charges based on your use of other services such as Amazon Elastic Compute Cloud (Amazon EC2)." @@ -547,4 +688,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/src/braket/experimental/algorithms/quantum_counting/__init__.py b/src/braket/experimental/algorithms/quantum_counting/__init__.py index 561b5e47..a9945f49 100644 --- a/src/braket/experimental/algorithms/quantum_counting/__init__.py +++ b/src/braket/experimental/algorithms/quantum_counting/__init__.py @@ -12,10 +12,8 @@ # language governing permissions and limitations under the License. from braket.experimental.algorithms.quantum_counting.quantum_counting import ( # noqa: F401, E501 - build_diffusion_matrix, - build_grover_matrix, - build_oracle_matrix, + build_grover_circuit, + build_oracle_circuit, get_quantum_counting_results, quantum_counting_circuit, - run_quantum_counting, ) diff --git a/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py b/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py index f56651f3..66f24967 100644 --- a/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py +++ b/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py @@ -1,16 +1,3 @@ -# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. - """Quantum Counting Algorithm implementation using the Amazon Braket SDK. The quantum counting algorithm combines Grover's search operator with Quantum @@ -27,71 +14,80 @@ import numpy as np -from braket.circuits import Circuit, circuit +from braket.circuits import Circuit from braket.circuits.qubit_set import QubitSetInput -from braket.devices import Device -from braket.tasks import QuantumTask +from braket.experimental.algorithms.grovers_search.grovers_search import amplify, build_oracle -def build_oracle_matrix(n_qubits: int, marked_states: List[int]) -> np.ndarray: - """Build a diagonal oracle matrix that flips the phase of marked states. +def build_oracle_circuit( + n_qubits: int, + marked_states: List[int], + decompose_ccnot: bool = False, +) -> Circuit: + """Build an oracle circuit that flips the phase of marked states. - The oracle acts as O|x> = -|x> for marked x, and O|x> = |x> otherwise. + Composes individual oracle circuits from grovers_search.build_oracle + for each marked state. Each call flips the phase of one basis state, + and their composition marks all specified states. Args: n_qubits (int): Number of qubits in the search register. marked_states (List[int]): Indices of marked computational-basis states. + decompose_ccnot (bool): Whether to decompose CCNOT (Toffoli) gates. Returns: - np.ndarray: The 2^n × 2^n diagonal oracle matrix. + Circuit: Oracle circuit that flips the phase of all marked states. Raises: ValueError: If a marked state index is out of range. """ dim = 2**n_qubits - oracle = np.eye(dim) for state in marked_states: if state < 0 or state >= dim: raise ValueError( f"Marked state {state} is out of range for {n_qubits} qubits " f"(must be in [0, {dim - 1}])." ) - oracle[state, state] = -1 - return oracle - - -def build_diffusion_matrix(n_qubits: int) -> np.ndarray: - """Build the Grover diffusion matrix D = 2|s> = H^{⊗n}|0>^{⊗n} is the uniform superposition state. + oracle_circ = Circuit() + for state in marked_states: + bitstring = format(state, f"0{n_qubits}b") + oracle_circ.add_circuit(build_oracle(bitstring, decompose_ccnot)) + return oracle_circ - Args: - n_qubits (int): Number of qubits in the search register. - Returns: - np.ndarray: The 2^n × 2^n diffusion matrix. - """ - dim = 2**n_qubits - s = np.ones(dim) / np.sqrt(dim) - return 2 * np.outer(s, s) - np.eye(dim) +def build_grover_circuit( + n_qubits: int, + marked_states: List[int], + decompose_ccnot: bool = False, +) -> Circuit: + """Build the Grover operator G = D · O as a circuit. + Uses circuit primitives from grovers_search: build_oracle for the phase + oracle and amplify for the diffusion operator (H · oracle_0 · H). -def build_grover_matrix(n_qubits: int, marked_states: List[int]) -> np.ndarray: - """Build the Grover operator G = D · O. + Note: + The MCZ ancilla decomposition introduces a global phase of -1 + relative to the ideal Grover matrix. This is accounted for + in get_quantum_counting_results during phase correction. Args: n_qubits (int): Number of qubits in the search register. marked_states (List[int]): Indices of marked states. + decompose_ccnot (bool): Whether to decompose CCNOT (Toffoli) gates. Returns: - np.ndarray: The 2^n × 2^n Grover operator matrix. + Circuit: Circuit implementing the Grover operator G. """ - oracle = build_oracle_matrix(n_qubits, marked_states) - diffusion = build_diffusion_matrix(n_qubits) - return diffusion @ oracle + oracle_circ = build_oracle_circuit(n_qubits, marked_states, decompose_ccnot) + diffusion_circ = amplify(n_qubits, decompose_ccnot) + + grover_circ = Circuit() + grover_circ.add_circuit(oracle_circ) + grover_circ.add_circuit(diffusion_circ) + return grover_circ -@circuit.subroutine(register=True) def inverse_qft_for_counting(qubits: QubitSetInput) -> Circuit: """Inverse Quantum Fourier Transform applied to the given qubits. @@ -118,7 +114,6 @@ def inverse_qft_for_counting(qubits: QubitSetInput) -> Circuit: return qft_circ -@circuit.subroutine(register=True) def controlled_grover( control: int, target_qubits: QubitSetInput, grover_unitary: np.ndarray ) -> Circuit: @@ -129,12 +124,8 @@ def controlled_grover( Args: control (int): Index of the control qubit. - target_qubits (QubitSetInput): Indices of target (search) qubits. - grover_unitary (np.ndarray): The Grover operator matrix. - - Returns: - Circuit: Circuit implementing the controlled Grover operator. - """ + target_qubits (QubitSetInput): Indices of target (search and ancilla) qubits. + """ circ = Circuit() # Build controlled unitary: |0><0| ⊗ I + |1><1| ⊗ U @@ -153,38 +144,51 @@ def quantum_counting_circuit( counting_circ: Circuit, counting_qubits: QubitSetInput, search_qubits: QubitSetInput, - grover_matrix: np.ndarray, + marked_states: List[int], + decompose_ccnot: bool = False, ) -> Circuit: """Create the full quantum counting circuit with result types. - Builds the quantum counting circuit comprising: - 1. Hadamard gates on all counting and search qubits - 2. Controlled-G^(2^k) for each counting qubit k - 3. Inverse QFT on the counting qubits - 4. Probability result type on all qubits + Builds the Grover operator as a circuit from grovers_search primitives + (build_oracle + amplify), extracts its unitary, and applies QPE. Args: counting_circ (Circuit): Initial circuit (may contain setup operations). counting_qubits (QubitSetInput): Qubits for the counting (precision) register. search_qubits (QubitSetInput): Qubits for the search register. - grover_matrix (np.ndarray): The Grover operator matrix G. + marked_states (List[int]): Indices of marked computational-basis states. + decompose_ccnot (bool): Whether to decompose CCNOT (Toffoli) gates. Returns: Circuit: The complete quantum counting circuit with result types. """ - return counting_circ.quantum_counting( - counting_qubits, search_qubits, grover_matrix - ).probability() + counting_circ.add_circuit( + quantum_counting( + counting_qubits, search_qubits, marked_states, decompose_ccnot + ) + ) + return counting_circ.probability(counting_qubits) -@circuit.subroutine(register=True) def quantum_counting( counting_qubits: QubitSetInput, search_qubits: QubitSetInput, - grover_matrix: np.ndarray, + marked_states: List[int], + decompose_ccnot: bool = False, ) -> Circuit: """Build the core quantum counting circuit using QPE on the Grover operator. + Constructs the Grover operator as a gate-level circuit from grovers_search + primitives (build_oracle for the phase oracle, amplify for the diffusion + operator), extracts its unitary via Circuit.to_unitary(), and applies + controlled-G^(2^k) for QPE. + + Note: + The MCZ ancilla decomposition in grovers_search introduces a global + phase of -1 on the Grover operator relative to the ideal matrix. + This shifts QPE phase estimates by 0.5. The correction is applied + in get_quantum_counting_results. + The circuit structure: 1. Apply H to all counting qubits 2. Apply H to all search qubits (prepare uniform superposition |s>) @@ -194,11 +198,26 @@ def quantum_counting( Args: counting_qubits (QubitSetInput): Qubits for the counting (precision) register. search_qubits (QubitSetInput): Qubits for the search register. - grover_matrix (np.ndarray): The Grover operator matrix G. + marked_states (List[int]): Indices of marked computational-basis states. + decompose_ccnot (bool): Whether to decompose CCNOT (Toffoli) gates. Returns: Circuit: Circuit implementing the quantum counting algorithm. """ + n_search = len(search_qubits) + + # Build the Grover operator circuit from grovers_search primitives + grover_circ = build_grover_circuit(n_search, marked_states, decompose_ccnot) + grover_unitary = grover_circ.to_unitary() + + # Determine ancilla qubits introduced by the circuit decomposition + n_ancilla = grover_circ.qubit_count - n_search + ancilla_qubits = [ + max(list(counting_qubits) + list(search_qubits)) + 1 + i + for i in range(n_ancilla) + ] + all_grover_qubits = list(search_qubits) + ancilla_qubits + qc_circ = Circuit() # Hadamard on counting qubits @@ -210,35 +229,18 @@ def quantum_counting( # Controlled-G^(2^k) for ii, qubit in enumerate(reversed(counting_qubits)): power = 2**ii - g_power = np.linalg.matrix_power(grover_matrix, power) - qc_circ.controlled_grover(qubit, search_qubits, g_power) + g_power = np.linalg.matrix_power(grover_unitary, power) + qc_circ.add_circuit(controlled_grover(qubit, all_grover_qubits, g_power)) # Inverse QFT on counting qubits - qc_circ.inverse_qft_for_counting(counting_qubits) + qc_circ.add_circuit(inverse_qft_for_counting(counting_qubits)) return qc_circ -def run_quantum_counting( - circuit: Circuit, - device: Device, - shots: int = 1000, -) -> QuantumTask: - """Run the quantum counting circuit on the given device. - - Args: - circuit (Circuit): The quantum counting circuit. - device (Device): Braket device backend. - shots (int): Number of measurement shots (default 1000). - - Returns: - QuantumTask: Task from running the quantum counting circuit. - """ - return device.run(circuit, shots=shots) - def get_quantum_counting_results( - task: QuantumTask, + task, counting_qubits: QubitSetInput, search_qubits: QubitSetInput, verbose: bool = False, @@ -281,13 +283,17 @@ def get_quantum_counting_results( ) # Convert counting register bitstrings to phase estimates and M estimates + # The MCZ ancilla decomposition introduces a global phase of -1 on the + # Grover operator, shifting QPE phase estimates by 0.5. We correct by + # computing: corrected_phase = |raw_phase - 0.5| phases, estimated_counts = _get_counting_estimates(counting_register_results, n_counting, N) # Best estimate from most frequent outcome if counting_register_results: best_key = max(counting_register_results, key=counting_register_results.get) best_y = int(best_key, 2) - best_phase = best_y / (2**n_counting) + raw_phase = best_y / (2**n_counting) + best_phase = abs(raw_phase - 0.5) best_M = N * (np.sin(np.pi * best_phase) ** 2) else: best_key = None @@ -303,12 +309,20 @@ def get_quantum_counting_results( } if verbose: - print(f"Measurement counts: {measurement_counts}") - print(f"Counting register results: {counting_register_results}") - print(f"Phase estimates: {phases}") - print(f"Estimated item counts: {estimated_counts}") - print(f"Best estimate of M: {best_M}") - print(f"Search space size N: {N}") + print(f"Search space size N = {N}") + sorted_cr = sorted( + counting_register_results.items(), key=lambda x: x[1], reverse=True + ) + print("\nCounting register distribution (top outcomes):") + for bitstring, count in sorted_cr[:6]: + y_val = int(bitstring, 2) + raw_ph = y_val / (2**n_counting) + ph = abs(raw_ph - 0.5) + m_est = N * (np.sin(np.pi * ph) ** 2) + print(f" |{bitstring}>: {count} counts -> phase = {ph:.4f}, M ~ {m_est:.4f}") + if len(sorted_cr) > 6: + print(f" ... ({len(sorted_cr) - 6} more outcomes)") + print(f"\nBest estimate of M: {best_M}") return aggregate_results @@ -334,7 +348,9 @@ def _get_counting_estimates( for bitstring in counting_register_results: y = int(bitstring, 2) - phase = y / (2**n_counting) + raw_phase = y / (2**n_counting) + # Correct for -1 global phase from MCZ decomposition + phase = abs(raw_phase - 0.5) M_est = N * (np.sin(np.pi * phase) ** 2) phases.append(phase) estimated_counts.append(M_est) diff --git a/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py b/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py index cffe214d..5136ca41 100644 --- a/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py +++ b/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py @@ -20,43 +20,43 @@ # ============================================================ -# Oracle / matrix construction tests +# Oracle / circuit construction tests # ============================================================ -def test_oracle_matrix_single_marked(): - """Oracle should flip the diagonal entry of the marked state to -1.""" - oracle = qc.build_oracle_matrix(2, [3]) - expected = np.diag([1, 1, 1, -1]) - np.testing.assert_array_equal(oracle, expected) +def test_oracle_circuit_single_marked(): + """Oracle circuit should flip the phase of the marked state.""" + oracle = qc.build_oracle_circuit(2, [3]) + assert len(oracle.instructions) > 0 + assert oracle.qubit_count >= 2 -def test_oracle_matrix_multiple_marked(): - """Oracle with multiple marked states should flip all corresponding entries.""" - oracle = qc.build_oracle_matrix(2, [0, 2]) - expected = np.diag([-1, 1, -1, 1]) - np.testing.assert_array_equal(oracle, expected) +def test_oracle_circuit_multiple_marked(): + """Oracle with multiple marked states should compose individual oracles.""" + oracle = qc.build_oracle_circuit(2, [0, 2]) + oracle_single = qc.build_oracle_circuit(2, [0]) + assert len(oracle.instructions) > len(oracle_single.instructions) -def test_oracle_matrix_no_marked(): - """Oracle with no marked states should be identity.""" - oracle = qc.build_oracle_matrix(2, []) - expected = np.eye(4) - np.testing.assert_array_equal(oracle, expected) +def test_oracle_circuit_no_marked(): + """Oracle with no marked states should be an empty circuit.""" + oracle = qc.build_oracle_circuit(2, []) + assert len(oracle.instructions) == 0 -def test_diffusion_matrix(): - """Diffusion matrix for 1-qubit should be [[0, 1], [1, 0]] (X gate).""" - diffusion = qc.build_diffusion_matrix(1) - expected = np.array([[0, 1], [1, 0]]) - np.testing.assert_array_almost_equal(diffusion, expected) +def test_grover_circuit_construction(): + """Grover circuit should combine oracle and diffusion.""" + grover = qc.build_grover_circuit(2, [1]) + assert len(grover.instructions) > 0 + assert grover.qubit_count >= 2 -def test_grover_matrix_unitarity(): - """Grover matrix should be unitary.""" - grover = qc.build_grover_matrix(2, [1]) - product = grover @ grover.T - np.testing.assert_array_almost_equal(product, np.eye(4), decimal=10) +def test_grover_circuit_unitarity(): + """Grover circuit unitary should be unitary.""" + grover = qc.build_grover_circuit(2, [1]) + u = grover.to_unitary() + product = u @ u.conj().T + np.testing.assert_array_almost_equal(product, np.eye(len(u)), decimal=10) # ============================================================ @@ -69,14 +69,11 @@ def test_quantum_counting_circuit_construction(): counting_qubits = [0, 1] search_qubits = [2] marked_states = [0] - grover = qc.build_grover_matrix(1, marked_states) circ = Circuit() - circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, grover) + circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, marked_states) - # The circuit should have instructions (Hadamard + controlled unitaries + QFT) assert len(circ.instructions) > 0 - # Should have result types (probability) assert len(circ.result_types) > 0 @@ -94,110 +91,241 @@ def test_inverse_qft_for_counting_2_qubits(): # ============================================================ +def _expected_M(n_counting: int, M_true: int, N: int) -> float: + """Compute the expected M estimate given finite counting-qubit precision. + + With n_counting qubits the QPE can only resolve phases in multiples of + 1/2^n_counting. This helper finds the closest representable phase to the + true Grover angle and returns the corresponding M estimate, which is what + an ideal (noiseless, infinite-shot) quantum counting run would produce. + """ + if M_true == 0: + return 0.0 + if M_true == N: + return float(N) + import math + + theta = math.asin(math.sqrt(M_true / N)) # Grover angle + exact_phase = theta / math.pi + # Closest representable phase with n_counting bits + y = round(exact_phase * (2**n_counting)) + approx_phase = y / (2**n_counting) + return N * (math.sin(math.pi * approx_phase) ** 2) + + def test_count_1_of_4(): - """Quantum counting should estimate M ≈ 1 for 1 marked item out of 4.""" + """Quantum counting should estimate M ≈ 1 for 1 marked item out of 4. + + With 4 counting qubits and N=4, the discretization error gives + M_expected ≈ 1.235 (from the closest phase 3/16 to the exact 1/6). + We allow a tolerance of 0.5 around the discretized expected value. + """ counting_qubits = [0, 1, 2, 3] search_qubits = [4, 5] marked_states = [3] - grover = qc.build_grover_matrix(2, marked_states) + N = 2 ** len(search_qubits) + M_exp = _expected_M(len(counting_qubits), len(marked_states), N) circ = Circuit() - circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, grover) + circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, marked_states) device = LocalSimulator() - task = qc.run_quantum_counting(circ, device, shots=1000) + task = device.run(circ, shots=1000) - results = qc.get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True) + count_estimates = qc.get_quantum_counting_results( + task, counting_qubits, search_qubits, verbose=True + ) - # Best estimate should be close to 1 - assert results["best_estimate"] is not None - assert results["search_space_size"] == 4 - assert abs(results["best_estimate"] - 1.0) < 1.5 + assert count_estimates["best_estimate"] is not None + assert count_estimates["search_space_size"] == N + assert abs(count_estimates["best_estimate"] - M_exp) < 0.5 def test_count_0_of_4(): - """Quantum counting should estimate M ≈ 0 when no items are marked.""" + """Quantum counting should estimate M ≈ 0 when no items are marked. + + With no marked items, the Grover operator is the identity (up to global + phase). QPE should measure phase 0, giving M = 0 exactly. + """ counting_qubits = [0, 1, 2, 3] search_qubits = [4, 5] marked_states = [] - grover = qc.build_grover_matrix(2, marked_states) circ = Circuit() - circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, grover) + circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, marked_states) device = LocalSimulator() - task = qc.run_quantum_counting(circ, device, shots=1000) + task = device.run(circ, shots=1000) - results = qc.get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True) + count_estimates = qc.get_quantum_counting_results( + task, counting_qubits, search_qubits, verbose=True + ) - # With no marked items, the most common measurement should yield M ≈ 0 - assert results["best_estimate"] is not None - assert abs(results["best_estimate"] - 0.0) < 0.5 + assert count_estimates["best_estimate"] is not None + assert abs(count_estimates["best_estimate"] - 0.0) < 0.01 def test_count_4_of_4(): - """Quantum counting should estimate M ≈ 4 when all items are marked.""" + """Quantum counting should estimate M ≈ 4 when all items are marked. + + With all items marked, the oracle flips every amplitude equally, so + QPE resolves the phase exactly and M = N. + """ counting_qubits = [0, 1, 2, 3] search_qubits = [4, 5] marked_states = [0, 1, 2, 3] - grover = qc.build_grover_matrix(2, marked_states) + N = 2 ** len(search_qubits) circ = Circuit() - circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, grover) + circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, marked_states) device = LocalSimulator() - task = qc.run_quantum_counting(circ, device, shots=1000) + task = device.run(circ, shots=1000) + + count_estimates = qc.get_quantum_counting_results( + task, counting_qubits, search_qubits, verbose=True + ) - results = qc.get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True) + assert count_estimates["best_estimate"] is not None + assert abs(count_estimates["best_estimate"] - float(N)) < 0.01 - # With all items marked, M should be ≈ 4 - assert results["best_estimate"] is not None - assert abs(results["best_estimate"] - 4.0) < 0.5 + +def test_count_3_of_4(): + """Quantum counting should estimate M ≈ 3 for 3 marked items out of 4. + + Complements the 1-of-4 test by verifying a non-trivial fraction (3/4). + With 4 counting qubits, the discretization error is small enough that + the estimate should be within 0.5 of the expected value. + """ + counting_qubits = [0, 1, 2, 3] + search_qubits = [4, 5] + marked_states = [0, 1, 3] + N = 2 ** len(search_qubits) + M_exp = _expected_M(len(counting_qubits), len(marked_states), N) + + circ = Circuit() + circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, marked_states) + + device = LocalSimulator() + task = device.run(circ, shots=1000) + + count_estimates = qc.get_quantum_counting_results( + task, counting_qubits, search_qubits, verbose=True + ) + + assert count_estimates["best_estimate"] is not None + assert abs(count_estimates["best_estimate"] - M_exp) < 0.5 def test_count_2_of_8(): - """Quantum counting should estimate M ≈ 2 for 2 marked items out of 8.""" + """Quantum counting should estimate M ≈ 2 for 2 marked items out of 8. + + With 5 counting qubits and N=8, the discretization error is small. + """ counting_qubits = [0, 1, 2, 3, 4] search_qubits = [5, 6, 7] marked_states = [2, 5] - grover = qc.build_grover_matrix(3, marked_states) + N = 2 ** len(search_qubits) + M_exp = _expected_M(len(counting_qubits), len(marked_states), N) circ = Circuit() - circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, grover) + circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, marked_states) device = LocalSimulator() - task = qc.run_quantum_counting(circ, device, shots=2000) + task = device.run(circ, shots=2000) - results = qc.get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True) + count_estimates = qc.get_quantum_counting_results( + task, counting_qubits, search_qubits, verbose=True + ) - # Best estimate should be close to 2 - assert results["best_estimate"] is not None - assert results["search_space_size"] == 8 - assert abs(results["best_estimate"] - 2.0) < 1.5 + assert count_estimates["best_estimate"] is not None + assert count_estimates["search_space_size"] == N + assert abs(count_estimates["best_estimate"] - M_exp) < 0.5 + + +def test_count_with_marked_initial_state(): + """QPE should estimate M correctly when search register starts in a marked state. + + Instead of the standard uniform superposition |s⟩ = H^⊗n|0⟩^⊗n, we + prepare the search register directly in a marked state |β⟩ = |11⟩. + Since |β⟩ is a superposition of both Grover eigenstates (with equal + amplitude), QPE still resolves the correct phase and produces the same + M estimate as the standard |s⟩ initialization. + + This validates that the algorithm works for initial states within the + Grover eigenspace beyond just the uniform superposition. + """ + counting_qubits = [0, 1, 2, 3] + search_qubits = [4, 5] + marked_states = [3] # Mark |11⟩ + N = 2 ** len(search_qubits) + M_exp = _expected_M(len(counting_qubits), len(marked_states), N) + + # Build the Grover circuit and extract its unitary + grover_circ = qc.build_grover_circuit(len(search_qubits), marked_states) + grover_unitary = grover_circ.to_unitary() + + # Determine ancilla qubits from circuit decomposition + n_ancilla = grover_circ.qubit_count - len(search_qubits) + ancilla_qubits = [ + max(counting_qubits + search_qubits) + 1 + i for i in range(n_ancilla) + ] + all_grover_qubits = list(search_qubits) + ancilla_qubits + + # Build custom QPE circuit with marked-state initialization + circ = Circuit() + + # QPE: Hadamard on counting qubits + circ.h(counting_qubits) + + # Prepare |β⟩ = |11⟩ (marked state) instead of uniform superposition + circ.x(search_qubits) + + # Controlled-G^(2^k) for QPE + for ii, qubit in enumerate(reversed(counting_qubits)): + power = 2 ** ii + g_power = np.linalg.matrix_power(grover_unitary, power) + circ.add_circuit(qc.controlled_grover(qubit, all_grover_qubits, g_power)) + + # Inverse QFT on counting qubits + circ.add_circuit(qc.inverse_qft_for_counting(counting_qubits)) + + # Measurement on counting register + circ.probability(counting_qubits) + + device = LocalSimulator() + task = device.run(circ, shots=1000) + + count_estimates = qc.get_quantum_counting_results( + task, counting_qubits, search_qubits, verbose=True + ) + + assert count_estimates["best_estimate"] is not None + assert abs(count_estimates["best_estimate"] - M_exp) < 0.5 def test_oracle_invalid_state_raises(): """Building oracle with out-of-range state should raise ValueError.""" try: - qc.build_oracle_matrix(2, [4]) # 4 is out of range for 2 qubits (max=3) + qc.build_oracle_circuit(2, [4]) # 4 is out of range for 2 qubits (max=3) assert False, "Should have raised ValueError" except ValueError: pass -def test_counting_results_have_correct_keys(): - """Results dict should contain all expected keys.""" +def test_counting_estimates_have_correct_keys(): + """Counting estimates dict should contain all expected keys.""" counting_qubits = [0, 1, 2] search_qubits = [3] - grover = qc.build_grover_matrix(1, [0]) + marked_states = [0] circ = Circuit() - circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, grover) + circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, marked_states) device = LocalSimulator() - task = qc.run_quantum_counting(circ, device, shots=100) + task = device.run(circ, shots=100) - results = qc.get_quantum_counting_results(task, counting_qubits, search_qubits) + count_estimates = qc.get_quantum_counting_results(task, counting_qubits, search_qubits) expected_keys = { "measurement_counts", @@ -207,12 +335,11 @@ def test_counting_results_have_correct_keys(): "best_estimate", "search_space_size", } - assert set(results.keys()) == expected_keys + assert set(count_estimates.keys()) == expected_keys def test_get_quantum_counting_results_empty_counts(): """Test get_quantum_counting_results with empty measurement counts.""" - # Mock task and result mock_task = MagicMock() mock_result = MagicMock() mock_result.measurement_counts = {} @@ -220,13 +347,11 @@ def test_get_quantum_counting_results_empty_counts(): counting_qubits = [0, 1] search_qubits = [2] - - # This should trigger the else block setting best_key and best_M to None - results = qc.get_quantum_counting_results(mock_task, counting_qubits, search_qubits) - - assert results["measurement_counts"] == {} - assert results["counting_register_results"] == {} - assert results["phases"] == [] - assert results["estimated_counts"] == [] - assert results["best_estimate"] is None + count_estimates = qc.get_quantum_counting_results(mock_task, counting_qubits, search_qubits) + + assert count_estimates["measurement_counts"] == {} + assert count_estimates["counting_register_results"] == {} + assert count_estimates["phases"] == [] + assert count_estimates["estimated_counts"] == [] + assert count_estimates["best_estimate"] is None From d83756669cadb54be78078af26b3e8ff8d51d09e Mon Sep 17 00:00:00 2001 From: axif Date: Wed, 25 Feb 2026 03:18:18 +0600 Subject: [PATCH 6/8] prevent in-place modification of the input `counting_circ` by composing a new circuit. --- .../algorithms/quantum_counting/quantum_counting.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py b/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py index 66f24967..78c0e373 100644 --- a/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py +++ b/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py @@ -162,12 +162,13 @@ def quantum_counting_circuit( Returns: Circuit: The complete quantum counting circuit with result types. """ - counting_circ.add_circuit( + new_circuit = Circuit().add_circuit(counting_circ) + new_circuit.add_circuit( quantum_counting( counting_qubits, search_qubits, marked_states, decompose_ccnot ) ) - return counting_circ.probability(counting_qubits) + return new_circuit.probability(counting_qubits) def quantum_counting( From 5b05e3f0d6d0b1974b2120f3233a606132db0876 Mon Sep 17 00:00:00 2001 From: axif Date: Fri, 27 Feb 2026 03:35:21 +0600 Subject: [PATCH 7/8] feat: Implement gate-level controlled Grover operator for Quantum Counting and add `run_quantum_counting` function. --- .../textbook/Quantum_Counting_Algorithm.ipynb | 228 +++++++++++----- .../algorithms/quantum_counting/__init__.py | 1 + .../quantum_counting/quantum_counting.py | 248 ++++++++++++++---- .../quantum_counting/test_quantum_counting.py | 69 +++-- 4 files changed, 404 insertions(+), 142 deletions(-) diff --git a/notebooks/textbook/Quantum_Counting_Algorithm.ipynb b/notebooks/textbook/Quantum_Counting_Algorithm.ipynb index e384164c..eb6b50d9 100644 --- a/notebooks/textbook/Quantum_Counting_Algorithm.ipynb +++ b/notebooks/textbook/Quantum_Counting_Algorithm.ipynb @@ -28,7 +28,14 @@ "cell_type": "code", "execution_count": 1, "id": "b9bdcb62", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-26T21:20:29.567098Z", + "iopub.status.busy": "2026-02-26T21:20:29.566767Z", + "iopub.status.idle": "2026-02-26T21:20:38.875569Z", + "shell.execute_reply": "2026-02-26T21:20:38.873798Z" + } + }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", @@ -41,6 +48,7 @@ " build_oracle_circuit,\n", " get_quantum_counting_results,\n", " quantum_counting_circuit,\n", + " run_quantum_counting,\n", ")\n", "\n", "%matplotlib inline" @@ -90,7 +98,14 @@ "cell_type": "code", "execution_count": 2, "id": "49c4b0e1", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-26T21:20:38.880338Z", + "iopub.status.busy": "2026-02-26T21:20:38.879028Z", + "iopub.status.idle": "2026-02-26T21:20:38.915409Z", + "shell.execute_reply": "2026-02-26T21:20:38.913644Z" + } + }, "outputs": [ { "name": "stdout", @@ -146,7 +161,14 @@ "cell_type": "code", "execution_count": 3, "id": "c7e1a2b3", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-26T21:20:38.925460Z", + "iopub.status.busy": "2026-02-26T21:20:38.924254Z", + "iopub.status.idle": "2026-02-26T21:20:38.970346Z", + "shell.execute_reply": "2026-02-26T21:20:38.969089Z" + } + }, "outputs": [ { "name": "stdout", @@ -207,7 +229,14 @@ "cell_type": "code", "execution_count": 4, "id": "d4537c2f", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-26T21:20:38.974567Z", + "iopub.status.busy": "2026-02-26T21:20:38.973858Z", + "iopub.status.idle": "2026-02-26T21:20:39.862187Z", + "shell.execute_reply": "2026-02-26T21:20:39.859359Z" + } + }, "outputs": [ { "name": "stdout", @@ -216,32 +245,44 @@ "Counting qubits (QPE register): [0, 1, 2, 3]\n", "Search qubits (data register): [4, 5]\n", "Search space size: N = 4\n", - "Marked states: [3] (M = 1)\n", + "Marked states: [3] (M = 1)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "\n", "Quantum Counting Circuit:\n", - "T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ 12 │ Result Types │\n", - " ┌───┐ ┌───┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌───┐ ┌─────────────┐ \n", - "q0 : ─┤ H ├───────────────────┤ U ├─────────────x────────────────────────────────────────────────────────────────────┤ PHASE(-0.39) ├───────┤ PHASE(-0.79) ├─┤ PHASE(-1.57) ├─┤ H ├─┤ Probability ├─\n", - " └───┘ └─┬─┘ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └───┘ └──────┬──────┘ \n", - " ┌───┐ ┌───┐ │ │ ┌──────────────┐ ┌──────────────┐ │ ┌───┐ │ │ ┌──────┴──────┐ \n", - "q1 : ─┤ H ├─────────────┤ U ├───┼──────x────────┼──────────────────────────────────┤ PHASE(-0.79) ├─┤ PHASE(-1.57) ├────────┼─────────┤ H ├────────┼────────────────●───────────────┤ Probability ├─\n", - " └───┘ └─┬─┘ │ │ │ └──────┬───────┘ └──────┬───────┘ │ └───┘ │ └──────┬──────┘ \n", - " ┌───┐ ┌───┐ │ │ │ │ ┌──────────────┐ ┌───┐ │ │ │ │ ┌──────┴──────┐ \n", - "q2 : ─┤ H ├───────┤ U ├───┼─────┼──────x────────┼───────────┤ PHASE(-1.57) ├─┤ H ├────────┼────────────────●────────────────┼──────────────────────●────────────────────────────────┤ Probability ├─\n", - " └───┘ └─┬─┘ │ │ │ └──────┬───────┘ └───┘ │ │ └──────┬──────┘ \n", - " ┌───┐ ┌───┐ │ │ │ │ ┌───┐ │ │ │ ┌──────┴──────┐ \n", - "q3 : ─┤ H ├─┤ U ├───┼─────┼─────┼───────────────x─────┤ H ├────────●──────────────────────●─────────────────────────────────●───────────────────────────────────────────────────────┤ Probability ├─\n", - " └───┘ └─┬─┘ │ │ │ └───┘ └─────────────┘ \n", - " ┌───┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ \n", - "q4 : ─┤ H ├─┤ U ├─┤ U ├─┤ U ├─┤ U ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n", - " └───┘ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ \n", - " ┌───┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ \n", - "q5 : ─┤ H ├─┤ U ├─┤ U ├─┤ U ├─┤ U ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n", - " └───┘ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ \n", - " ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ \n", - "q6 : ───────┤ U ├─┤ U ├─┤ U ├─┤ U ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n", - " └───┘ └───┘ └───┘ └───┘ \n", - "T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ 12 │ Result Types │\n" + "T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ 12 │ 13 │ 14 │ 15 │ 16 │ 17 │ 18 │ 19 │ 20 │ 21 │ 22 │ 23 │ 24 │ 25 │ 26 │ 27 │ 28 │ 29 │ 30 │ 31 │ 32 │ 33 │ 34 │ 35 │ 36 │ 37 │ 38 │ 39 │ 40 │ 41 │ 42 │ 43 │ 44 │ 45 │ 46 │ 47 │ 48 │ 49 │ 50 │ 51 │ 52 │ 53 │ 54 │ 55 │ 56 │ 57 │ 58 │ 59 │ 60 │ 61 │ 62 │ 63 │ 64 │ 65 │ 66 │ 67 │ 68 │ 69 │ 70 │ 71 │ 72 │ 73 │ 74 │ 75 │ 76 │ 77 │ 78 │ 79 │ 80 │ 81 │ 82 │ 83 │ 84 │ 85 │ 86 │ 87 │ 88 │ 89 │ 90 │ 91 │ 92 │ 93 │ 94 │ 95 │ 96 │ 97 │ 98 │ 99 │ 100 │ 101 │ 102 │ 103 │ 104 │ 105 │ 106 │ 107 │ 108 │ 109 │ 110 │ 111 │ 112 │ 113 │ 114 │ 115 │ 116 │ 117 │ 118 │ 119 │ 120 │ 121 │ 122 │ 123 │ 124 │ 125 │ 126 │ 127 │ 128 │ 129 │ 130 │ 131 │ 132 │ 133 │ 134 │ 135 │ 136 │ 137 │ 138 │ 139 │ 140 │ 141 │ 142 │ 143 │ 144 │ 145 │ 146 │ 147 │ 148 │ 149 │ 150 │ 151 │ 152 │ 153 │ 154 │ 155 │ 156 │ 157 │ 158 │ 159 │ 160 │ 161 │ 162 │ 163 │ 164 │ 165 │ 166 │ 167 │ 168 │ 169 │ 170 │ 171 │ 172 │ 173 │ 174 │ 175 │ 176 │ 177 │ 178 │ 179 │ 180 │ 181 │ 182 │ 183 │ 184 │ 185 │ 186 │ 187 │ 188 │ 189 │ 190 │ 191 │ 192 │ 193 │ 194 │ 195 │ 196 │ 197 │ 198 │ 199 │ 200 │ 201 │ 202 │ 203 │ 204 │ 205 │ 206 │ 207 │ 208 │ 209 │ 210 │ 211 │ 212 │ 213 │ 214 │ 215 │ 216 │ 217 │ 218 │ 219 │ 220 │ 221 │ 222 │ 223 │ 224 │ 225 │ 226 │ 227 │ 228 │ 229 │ 230 │ 231 │ 232 │ 233 │ 234 │ 235 │ 236 │ 237 │ 238 │ 239 │ 240 │ 241 │ 242 │ 243 │ 244 │ 245 │ 246 │ 247 │ 248 │ 249 │ 250 │ 251 │ 252 │ 253 │ 254 │ 255 │ 256 │ 257 │ 258 │ 259 │ 260 │ 261 │ 262 │ 263 │ 264 │ 265 │ 266 │ 267 │ 268 │ 269 │ 270 │ 271 │ 272 │ 273 │ 274 │ 275 │ 276 │ 277 │ 278 │ 279 │ 280 │ 281 │ 282 │ 283 │ 284 │ 285 │ 286 │ 287 │ 288 │ 289 │ 290 │ 291 │ 292 │ 293 │ 294 │ 295 │ 296 │ 297 │ 298 │ 299 │ 300 │ 301 │ 302 │ 303 │ 304 │ 305 │ 306 │ 307 │ 308 │ 309 │ 310 │ 311 │ 312 │ 313 │ 314 │ 315 │ 316 │ 317 │ 318 │ 319 │ 320 │ 321 │ 322 │ 323 │ 324 │ 325 │ 326 │ 327 │ 328 │ 329 │ 330 │ 331 │ 332 │ 333 │ 334 │ 335 │ 336 │ 337 │ 338 │ 339 │ 340 │ 341 │ 342 │ 343 │ 344 │ 345 │ 346 │ 347 │ 348 │ 349 │ 350 │ 351 │ 352 │ 353 │ 354 │ 355 │ 356 │ 357 │ 358 │ 359 │ 360 │ 361 │ 362 │ 363 │ 364 │ 365 │ Result Types │\n", + " ┌───┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌───┐ ┌─────────────┐ \n", + "q0 : ─┤ H ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────●───────────────────────────────────────────────────────────────────────────────────●───────────────────────●────────────●────────────●───────────────────────────────────────────●─────────────────────────────●────────────●────────────●─────────────────────────────────────●───────────────────────●────────────●────────────●───────────────────────────────────────────●─────────────────────────────●────────────●────────────●─────────────────────────────────────●───────────────────────●────────────●────────────●───────────────────────────────────────────●─────────────────────────────●────────────●────────────●─────────────────────────────────────●───────────────────────●────────────●────────────●───────────────────────────────────────────●─────────────────────────────●────────────●────────────●─────────────────────────────────────●───────────────────────●────────────●────────────●───────────────────────────────────────────●─────────────────────────────●────────────●────────────●─────────────────────────────────────●───────────────────────●────────────●────────────●───────────────────────────────────────────●─────────────────────────────●────────────●────────────●─────────────────────────────────────●───────────────────────●────────────●────────────●───────────────────────────────────────────●─────────────────────────────●────────────●────────────●─────────────────────────────────────●───────────────────────●────────────●────────────●───────────────────────────────────────────●─────────────────────────────●────────────●──────x─────────────────────────────────────────────────────────────────────┤ PHASE(-0.39) ├───────┤ PHASE(-0.79) ├─┤ PHASE(-1.57) ├─┤ H ├─┤ Probability ├─\n", + " └───┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └───┘ └──────┬──────┘ \n", + " ┌───┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ ┌───┐ │ │ ┌──────┴──────┐ \n", + "q1 : ─┤ H ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────●─────────────────────────────────────────────────────────────────────────────────●───────────────────────●────────────●────────────●───────────────────────────────────────────●─────────────────────────────●────────────●────────────●─────────────────────────────────────●───────────────────────●────────────●────────────●───────────────────────────────────────────●─────────────────────────────●────────────●────────────●─────────────────────────────────────●───────────────────────●────────────●────────────●───────────────────────────────────────────●─────────────────────────────●────────────●────────────●─────────────────────────────────────●───────────────────────●────────────●────────────●───────────────────────────────────────────●───────────┼───────────────────────●────────────●──────x───────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼──────┼───────────────────────────────────┤ PHASE(-0.79) ├─┤ PHASE(-1.57) ├────────┼─────────┤ H ├────────┼────────────────●───────────────┤ Probability ├─\n", + " └───┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └──────┬───────┘ └──────┬───────┘ │ └───┘ │ └──────┬──────┘ \n", + " ┌───┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌──────────────┐ ┌───┐ │ │ │ │ ┌──────┴──────┐ \n", + "q2 : ─┤ H ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────●─────────────────────────────────────────────────────────────────────────────────●───────────────────────●────────────●────────────●───────────────────────────────────────────●─────────────────────────────●────────────●────────────●─────────────────────────────────────●───────────────────────●────────────●────────────●───────────────────────────────────────────●───────────┼───────────────────────●────────────●────────────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼───────────┼───────────────────────┼────────────┼──────x───────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼──────┼────────────┤ PHASE(-1.57) ├─┤ H ├────────┼────────────────●────────────────┼──────────────────────●────────────────────────────────┤ Probability ├─\n", + " └───┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └──────┬───────┘ └───┘ │ │ └──────┬──────┘ \n", + " ┌───┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌───┐ │ │ │ ┌──────┴──────┐ \n", + "q3 : ─┤ H ├───●───────────────────────●───────────────────────●────────────●────────────●───────────────────────────────────────────●───────────┼───────────────────────●────────────●────────────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼───────────┼───────────────────────┼────────────┼────────────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼───────────┼───────────────────────┼────────────┼──────────────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼────────────┼─────────────────────────────────────┼───────────────────────┼────────────┼────────────┼───────────────────────────────────────────┼─────────────────────────────┼────────────┼──────x─────┤ H ├─────────●──────────────────────●─────────────────────────────────●───────────────────────────────────────────────────────┤ Probability ├─\n", + " └───┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └───┘ └─────────────┘ \n", + " ┌───┐ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ ┌───┐ │ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ ┌───┐ │ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ ┌───┐ │ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ │ ┌────┐ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ \n", + "q4 : ─┤ H ├───┼─────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├─┤ X ├──────────●───────────●─────┼───┤ X ├───┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├──────────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├─┤ X ├──────────●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├──────────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├─┤ X ├──────────●───────────●─────┼───┤ X ├───┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├──────────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├─┤ X ├──────────●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├──────────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├─┤ X ├──────────●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├──────────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├─┤ X ├──────────●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├──────────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├─┤ X ├──────────●───────────●─────┼───┤ X ├───┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼────┤ H ├───┤ Si ├──────────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├─┤ X ├──────────●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├──────────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├─┤ X ├──────────●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├──────────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├─┤ X ├──────────●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├──────────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├─┤ X ├──────────●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├──────────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├─┤ X ├──────────●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├──────────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├─┤ X ├──────────●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├──────────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├─┤ X ├──────────●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├──────────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼───┤ H ├────┼───┤ Si ├─┤ X ├──────────●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├─┤ X ├─┤ Ti ├───┼────┤ H ├───┤ Si ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n", + " └───┘ │ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ └───┘ │ │ │ └───┘ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ └───┘ │ │ │ └───┘ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ └───┘ │ │ │ └───┘ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ │ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ \n", + " ┌───┐ │ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ ┌───┐ │ │ │ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ ┌───┐ ┌────┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ ┌───┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ ┌───┐ │ │ │ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ ┌───┐ ┌────┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ ┌───┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ ┌───┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ ┌───┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ ┌───┐ │ │ │ ┌───┐ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ ┌───┐ ┌────┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ ┌───┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ ┌───┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ ┌───┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ ┌───┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ ┌───┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ ┌───┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ ┌───┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ │ ┌───┐ ┌────┐ ┌───┐ │ │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌────┐ ┌───┐ ┌────┐ \n", + "q5 : ─┤ H ├───┼─────●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├─┤ X ├───●───────────●─────┼───┤ X ├───┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├─┤ H ├──┤ Si ├───●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├─┤ X ├───●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├───●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├─┤ X ├───●───────────●─────┼───┤ X ├───┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├─┤ H ├──┤ Si ├───●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├─┤ X ├───●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├───●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├─┤ X ├───●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├───●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├─┤ X ├───●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├───●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├─┤ X ├───●───────────●─────┼───┤ X ├───┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├──┤ Ti ├──┤ H ├──┤ Si ├───●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├─┤ X ├───●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├───●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├─┤ X ├───●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├───●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├─┤ X ├───●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├───●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├─┤ X ├───●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├───●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├─┤ X ├───●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├───●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├─┤ X ├───●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├───●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├─┤ X ├───●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├───●───────────●─────┼───┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├─┤ Ti ├───┼───┤ H ├──┤ Si ├─┤ X ├───●───────────●─────┼───┤ X ├─┤ S ├─┤ H ├─┤ T ├──────────────┤ X ├──┤ Ti ├──┤ H ├───────┤ Si ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n", + " └───┘ │ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ └───┘ │ │ │ └───┘ │ └───┘ └───┘ └───┘ └───┘ └────┘ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ └───┘ │ │ │ └───┘ │ └───┘ └───┘ └───┘ └───┘ └────┘ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ └───┘ │ │ │ └───┘ │ └───┘ └───┘ └───┘ └───┘ └────┘ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └────┘ │ └───┘ └────┘ └───┘ │ │ │ └───┘ └───┘ └───┘ └───┘ └───┘ └────┘ └───┘ └────┘ \n", + " ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ ┌─┴─┐ │ │ ┌─┴─┐ \n", + "q6 : ───────┤ X ├───┼─────●─────┼───┤ X ├─────────────────────────────────────────────┤ X ├───────────────────────┼─────●─────┼───┤ X ├───────┤ X ├─────────────────────────────────────────────────────────────┼─────●─────┼───┤ X ├─────────────────────────────────────────────┤ X ├───────────────────────┼─────●─────┼───┤ X ├───────────────────────────────────────────────────┤ X ├─────────────────┼─────●─────┼───┤ X ├─────────────────────────────────────────────┤ X ├───────────────────────┼─────●─────┼───┤ X ├───────┤ X ├─────────────────────────────────────────────────────────────┼─────●─────┼───┤ X ├─────────────────────────────────────────────┤ X ├───────────────────────┼─────●─────┼───┤ X ├───────────────────────────────────────────────────┤ X ├─────────────────┼─────●─────┼───┤ X ├─────────────────────────────────────────────┤ X ├───────────────────────┼─────●─────┼───┤ X ├───────────────────────────────────────────────────┤ X ├─────────────────┼─────●─────┼───┤ X ├─────────────────────────────────────────────┤ X ├───────────────────────┼─────●─────┼───┤ X ├───────────────────────────────────────────────────┤ X ├─────────────────┼─────●─────┼───┤ X ├─────────────────────────────────────────────┤ X ├───────────────────────┼─────●─────┼───┤ X ├───────┤ X ├───────────────────────────────────────────────────────────────┼─────●─────┼───┤ X ├─────────────────────────────────────────────┤ X ├───────────────────────┼─────●─────┼───┤ X ├───────────────────────────────────────────────────┤ X ├─────────────────┼─────●─────┼───┤ X ├─────────────────────────────────────────────┤ X ├───────────────────────┼─────●─────┼───┤ X ├───────────────────────────────────────────────────┤ X ├─────────────────┼─────●─────┼───┤ X ├─────────────────────────────────────────────┤ X ├───────────────────────┼─────●─────┼───┤ X ├───────────────────────────────────────────────────┤ X ├─────────────────┼─────●─────┼───┤ X ├─────────────────────────────────────────────┤ X ├───────────────────────┼─────●─────┼───┤ X ├───────────────────────────────────────────────────┤ X ├─────────────────┼─────●─────┼───┤ X ├─────────────────────────────────────────────┤ X ├───────────────────────┼─────●─────┼───┤ X ├───────────────────────────────────────────────────┤ X ├─────────────────┼─────●─────┼───┤ X ├─────────────────────────────────────────────┤ X ├───────────────────────┼─────●─────┼───┤ X ├───────────────────────────────────────────────────┤ X ├─────────────────┼─────●─────┼───┤ X ├─────────────────────────────────────────────┤ X ├───────────────────────┼─────●─────┼───┤ X ├───────────────────────────────────────────────────┤ X ├─────────────────┼─────●─────┼───┤ X ├─────────────────────────────────────────────┤ X ├───────────────────────┼─────●─────┼───┤ X ├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n", + " └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ └───┘ │ │ │ └───┘ \n", + " ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ ┌─┴─┐ │ ┌─┴─┐ \n", + "q7 : ─────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├───────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├─────────────────────────────────────────────────────────────────────────────┤ X ├───●───┤ X ├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n", + " └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ └───┘ │ └───┘ \n", + " ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┴─┐ ┌───┐ ┌───┐ \n", + "q8 : ─┤ X ├─┤ H ├───────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├───────┤ X ├─┤ H ├─────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├───────┤ X ├─┤ H ├─────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├───────┤ X ├─┤ H ├───────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├─┤ X ├─┤ H ├───────────────────────────────────────────────────────────┤ X ├─┤ H ├───────┤ X ├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n", + " └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ \n", + "T : │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ 12 │ 13 │ 14 │ 15 │ 16 │ 17 │ 18 │ 19 │ 20 │ 21 │ 22 │ 23 │ 24 │ 25 │ 26 │ 27 │ 28 │ 29 │ 30 │ 31 │ 32 │ 33 │ 34 │ 35 │ 36 │ 37 │ 38 │ 39 │ 40 │ 41 │ 42 │ 43 │ 44 │ 45 │ 46 │ 47 │ 48 │ 49 │ 50 │ 51 │ 52 │ 53 │ 54 │ 55 │ 56 │ 57 │ 58 │ 59 │ 60 │ 61 │ 62 │ 63 │ 64 │ 65 │ 66 │ 67 │ 68 │ 69 │ 70 │ 71 │ 72 │ 73 │ 74 │ 75 │ 76 │ 77 │ 78 │ 79 │ 80 │ 81 │ 82 │ 83 │ 84 │ 85 │ 86 │ 87 │ 88 │ 89 │ 90 │ 91 │ 92 │ 93 │ 94 │ 95 │ 96 │ 97 │ 98 │ 99 │ 100 │ 101 │ 102 │ 103 │ 104 │ 105 │ 106 │ 107 │ 108 │ 109 │ 110 │ 111 │ 112 │ 113 │ 114 │ 115 │ 116 │ 117 │ 118 │ 119 │ 120 │ 121 │ 122 │ 123 │ 124 │ 125 │ 126 │ 127 │ 128 │ 129 │ 130 │ 131 │ 132 │ 133 │ 134 │ 135 │ 136 │ 137 │ 138 │ 139 │ 140 │ 141 │ 142 │ 143 │ 144 │ 145 │ 146 │ 147 │ 148 │ 149 │ 150 │ 151 │ 152 │ 153 │ 154 │ 155 │ 156 │ 157 │ 158 │ 159 │ 160 │ 161 │ 162 │ 163 │ 164 │ 165 │ 166 │ 167 │ 168 │ 169 │ 170 │ 171 │ 172 │ 173 │ 174 │ 175 │ 176 │ 177 │ 178 │ 179 │ 180 │ 181 │ 182 │ 183 │ 184 │ 185 │ 186 │ 187 │ 188 │ 189 │ 190 │ 191 │ 192 │ 193 │ 194 │ 195 │ 196 │ 197 │ 198 │ 199 │ 200 │ 201 │ 202 │ 203 │ 204 │ 205 │ 206 │ 207 │ 208 │ 209 │ 210 │ 211 │ 212 │ 213 │ 214 │ 215 │ 216 │ 217 │ 218 │ 219 │ 220 │ 221 │ 222 │ 223 │ 224 │ 225 │ 226 │ 227 │ 228 │ 229 │ 230 │ 231 │ 232 │ 233 │ 234 │ 235 │ 236 │ 237 │ 238 │ 239 │ 240 │ 241 │ 242 │ 243 │ 244 │ 245 │ 246 │ 247 │ 248 │ 249 │ 250 │ 251 │ 252 │ 253 │ 254 │ 255 │ 256 │ 257 │ 258 │ 259 │ 260 │ 261 │ 262 │ 263 │ 264 │ 265 │ 266 │ 267 │ 268 │ 269 │ 270 │ 271 │ 272 │ 273 │ 274 │ 275 │ 276 │ 277 │ 278 │ 279 │ 280 │ 281 │ 282 │ 283 │ 284 │ 285 │ 286 │ 287 │ 288 │ 289 │ 290 │ 291 │ 292 │ 293 │ 294 │ 295 │ 296 │ 297 │ 298 │ 299 │ 300 │ 301 │ 302 │ 303 │ 304 │ 305 │ 306 │ 307 │ 308 │ 309 │ 310 │ 311 │ 312 │ 313 │ 314 │ 315 │ 316 │ 317 │ 318 │ 319 │ 320 │ 321 │ 322 │ 323 │ 324 │ 325 │ 326 │ 327 │ 328 │ 329 │ 330 │ 331 │ 332 │ 333 │ 334 │ 335 │ 336 │ 337 │ 338 │ 339 │ 340 │ 341 │ 342 │ 343 │ 344 │ 345 │ 346 │ 347 │ 348 │ 349 │ 350 │ 351 │ 352 │ 353 │ 354 │ 355 │ 356 │ 357 │ 358 │ 359 │ 360 │ 361 │ 362 │ 363 │ 364 │ 365 │ Result Types │\n" ] } ], @@ -274,9 +315,16 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "8a31859a", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-26T21:20:39.865257Z", + "iopub.status.busy": "2026-02-26T21:20:39.864934Z", + "iopub.status.idle": "2026-02-26T21:20:41.511716Z", + "shell.execute_reply": "2026-02-26T21:20:41.495119Z" + } + }, "outputs": [ { "name": "stdout", @@ -285,12 +333,12 @@ "Search space size N = 4\n", "\n", "Counting register distribution (top outcomes):\n", - " |1011>: 369 counts -> phase = 0.1875, M ~ 1.2346\n", - " |0101>: 345 counts -> phase = 0.1875, M ~ 1.2346\n", - " |1010>: 77 counts -> phase = 0.1250, M ~ 0.5858\n", - " |0110>: 76 counts -> phase = 0.1250, M ~ 0.5858\n", - " |1100>: 28 counts -> phase = 0.2500, M ~ 2.0000\n", - " |0111>: 22 counts -> phase = 0.0625, M ~ 0.1522\n", + " |0101>: 339 counts -> phase = 0.1875, M ~ 1.2346\n", + " |1011>: 332 counts -> phase = 0.1875, M ~ 1.2346\n", + " |1010>: 109 counts -> phase = 0.1250, M ~ 0.5858\n", + " |0110>: 97 counts -> phase = 0.1250, M ~ 0.5858\n", + " |0100>: 27 counts -> phase = 0.2500, M ~ 2.0000\n", + " |0111>: 21 counts -> phase = 0.0625, M ~ 0.1522\n", " ... (10 more outcomes)\n", "\n", "Best estimate of M: 1.2346331352698203\n", @@ -304,12 +352,12 @@ ], "source": [ "device = LocalSimulator()\n", - "task = device.run(circ, shots=1000)\n", + "task = run_quantum_counting(circ, device, shots=1000)\n", "\n", "# Process results - uses only the counting register\n", "results = get_quantum_counting_results(task, counting_qubits, search_qubits, verbose=True)\n", "\n", - "print(f\"\\n--- Summary ---\")\n", + "print(\"\\n--- Summary ---\")\n", "print(f\"Actual M = {len(marked_states)}\")\n", "print(f\"Estimated M = {results['best_estimate']:.4f}\")\n", "print(f\"Absolute error: {abs(len(marked_states) - results['best_estimate']):.4f}\")" @@ -319,11 +367,18 @@ "cell_type": "code", "execution_count": 6, "id": "2ef4d059", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-26T21:20:41.519644Z", + "iopub.status.busy": "2026-02-26T21:20:41.519231Z", + "iopub.status.idle": "2026-02-26T21:20:43.233794Z", + "shell.execute_reply": "2026-02-26T21:20:43.230430Z" + } + }, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAHqCAYAAAAZLi26AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAbupJREFUeJzt3Xd4FOX6//HP0hJaEkJJQAIEkBIIRWroQqSKeMAuAkqxUMSKWAELdjkq4ldUEBTxiIgHRKkCoqCAIh2pgkIABRJqQpL79we/3ZOFBELIspvh/bquvWBnZmfue59nJntPdZmZCQAAAAAA5Lp8/g4AAAAAAACnougGAAAAAMBHKLoBAAAAAPARim4AAAAAAHyEohsAAAAAAB+h6AYAAAAAwEcougEAAAAA8BGKbgAAAAAAfISiGwAAAAAAH6HoBgAgD+jTp48qVark7zAC0sSJE+VyubRz506fL+s///mPwsPDdfToUZ8v63L32GOPqUmTJv4OAwAuGkU3AAS49evXq2fPnrriiisUFBSkcuXKqWfPntqwYYO/Q/OyYcMGjRgx4pIUPjn15ZdfqlOnTipVqpQKFSqkcuXK6aabbtLChQv9HZokac+ePRoxYoRWr17t71C8tGnTRi6Xy/MqXLiw6tSpozFjxig9Pd3f4WXqnXfe0cSJE3N1nmlpaXrmmWc0ePBgFStWzDO8UqVKcrlcGjx48FmfWbRokVwul6ZNm5arsUhS//795XK5dO211+Z4Hu4dFi6XS0uXLj1rvJkpKirqopeT0bhx43TjjTeqQoUKcrlc6tOnT6bTDR06VL/99pv++9//5spyAcBfKLoBIIBNnz5dV111lRYsWKA777xT77zzjvr27auFCxfqqquu0ldffeXvED02bNigkSNHBmTRbWa688471b17d+3bt08PPvig3n33XQ0cOFDbt29Xu3bt9OOPP/o7TO3Zs0cjR47MtOgeP368Nm/efOmD+v/Kly+vyZMna/LkyRo9erSCg4P1wAMP6KmnnvJbTOfii6J75syZ2rx5swYMGJDp+PHjx2vPnj25usysrFy5UhMnTlRwcHCuzC84OFhTpkw5a/jixYv1559/KigoKFeWI0kvvfSSFi5cqFq1aqlAgQJZThcZGalu3brp1VdfzbVlA4A/ZL2lAwD41bZt23THHXeocuXKWrJkiUqXLu0Zd//996tly5bq2bOn1qxZo+joaD9GGvhee+01TZw4UUOHDtXrr78ul8vlGffEE09o8uTJ5/zxHwgKFizo1+WHhoaqZ8+envf33HOPatSoobfeekujRo1S/vz5/RjdpTFhwgQ1b95cV1xxxVnjatWqpc2bN+vFF1/Um2++6dM4zExDhgxRr169tGDBglyZZ+fOnfX555/rzTff9FoXpkyZogYNGujvv//OleVIpwt591HujGcMZOamm27SjTfeqO3bt6ty5cq5FgMAXEoc6QaAAPXKK6/o+PHjeu+997wKbkkqVaqU/u///k9Hjx7VK6+84hme1XW/I0aM8Co0pdMFRNu2bVWmTBkFBQUpJiZG48aNO+uzlSpV0rXXXqulS5eqcePGCg4OVuXKlTVp0iTPNBMnTtSNN94oSbr66qs9p6suWrRIkuRyuTRixIhM553x1FL3qa5Lly7VkCFDVLp0aYWFhenuu+9WSkqKDh8+rF69eqlEiRIqUaKEHn30UZnZOb/HEydOaPTo0apRo4ZeffXVs74HSbrjjjvUuHFjz/vt27frxhtvVHh4uIoUKaKmTZvq66+/9vpMVtcRu08nducunT49u3bt2tqwYYOuvvpqFSlSRFdccYVefvllr881atRIknTnnXd6vkP30doz23bnzp1yuVx69dVX9d5776lKlSoKCgpSo0aNtGLFirNy/PzzzxUTE6Pg4GDVrl1bX3755UVdJx4cHKxGjRrpyJEj2r9/v9e4jz/+WA0aNFDhwoUVHh6uW265Rbt37/aaZsuWLerRo4ciIyMVHBys8uXL65ZbblFiYqJXfpkdrc6qP7lVqlRJ69ev1+LFiz3fY5s2bSRJp06d0siRI3XllVcqODhYJUuWVIsWLTRv3rxz5nvy5El9++23io+Pz3KZvXr1uiRHuydPnqx169bp+eefz7V53nrrrfrnn3+8voeUlBRNmzZNt912W64tR5IqVqyY6XqYGff3HUhn9QDAhQrs3foAcBmbOXOmKlWqpJYtW2Y6vlWrVqpUqZJmzpypd95554LnP27cONWqVUvXXXedChQooJkzZ+q+++5Tenq6Bg4c6DXt1q1bdcMNN6hv377q3bu3PvzwQ/Xp00cNGjRQrVq11KpVKw0ZMkRvvvmmHn/8cdWsWVOSPP9eqMGDBysyMlIjR47U8uXL9d577yksLEw//vijKlSooBdeeEGzZ8/WK6+8otq1a6tXr15Zzmvp0qU6ePCghg4dmq2jsfv27VOzZs10/PhxDRkyRCVLltRHH32k6667TtOmTdO//vWvHOV06NAhdezYUd27d9dNN92kadOmadiwYYqNjVWnTp1Us2ZNjRo1Sk8//bQGDBjgafdmzZqdc75TpkzRkSNHdPfdd8vlcunll19W9+7dtX37ds/R8a+//lo333yzYmNjNXr0aB06dEh9+/bN9IjthXAXxmFhYZ5hzz//vJ566inddNNN6tevnw4cOKC33npLrVq10q+//qqwsDClpKSoQ4cOSk5O9rT1X3/9pVmzZunw4cMKDQ29qLjGjBnjue76iSeekCRFRERIOr0DavTo0erXr58aN26spKQkrVy5Ur/88ouuueaaLOe5atUqpaSk6KqrrspymieeeEKTJk0679HuU6dOeXYunE94eLjy5fvfMZIjR45o2LBhevzxxxUZGZmteWRHpUqVFBcXp08//VSdOnWSJH3zzTdKTEzULbfckmk+hw4dUlpa2nnnXaRIERUpUiRHcYWGhqpKlSr64Ycf9MADD+RoHgDgdwYACDiHDx82SdatW7dzTnfdddeZJEtKSjIzs969e1vFihXPmu6ZZ56xMzf5x48fP2u6Dh06WOXKlb2GVaxY0STZkiVLPMP2799vQUFB9tBDD3mGff755ybJvvvuu7PmK8meeeaZs4ZXrFjRevfu7Xk/YcIEk2QdOnSw9PR0z/C4uDhzuVx2zz33eIalpqZa+fLlrXXr1mfNN6N///vfJsm+/PLLc07nNnToUJNk33//vWfYkSNHLDo62ipVqmRpaWlese7YscPr8999991Z30Pr1q1Nkk2aNMkzLDk52SIjI61Hjx6eYStWrDBJNmHChLPiOrNtd+zYYZKsZMmSdvDgQc/wr776yiTZzJkzPcNiY2OtfPnyduTIEc+wRYsWmaRM+8uZWrdubTVq1LADBw7YgQMHbNOmTfbII4+YJOvSpYtnup07d1r+/Pnt+eef9/r82rVrrUCBAp7hv/76q0myzz//PMtluvPL7Ls4sz9l1ha1atXKtG/UrVvXK+bsev/9902SrV279qxxFStW9MzzzjvvtODgYNuzZ4+Z/a8/ZMzVPSw7rzP718MPP2zR0dF28uTJs5adE+7vbsWKFfb2229b8eLFPduGG2+80a6++uosl+PeNpzvldm671a0aFGvbUBm2rdvbzVr1sxxjgDgbxzpBoAAdOTIEUlS8eLFzzmde/yRI0fOO+2ZChcu7Pl/YmKiTp06pdatW2vOnDlKTEz0OtoYExPjdcS9dOnSql69urZv335By8yuvn37ep1+2qRJEy1btkx9+/b1DMufP78aNmyoVatWnXNeSUlJks7/XbrNnj1bjRs3VosWLTzDihUrpgEDBmj48OHasGGDateufSHpeOaR8ZroQoUKqXHjxhf9Hd58880qUaKE5727ndzz3bNnj9auXavHH3/c6/rZ1q1bKzY21vP9nM+mTZvOuszhuuuu0wcffOB5P336dKWnp+umm27yugY4MjJSV155pb777js9/vjjnr41Z84cde7cOcdHQXMiLCxM69ev15YtW3TllVdm+3P//POPJHl915l58sknNXnyZL344ov697//nek0devWPe/p7G4Zj2b//vvv+ve//61PP/00V29s5nbTTTdp6NChmjVrljp27KhZs2ad84j9J598ohMnTpx3vhd7LXaJEiX066+/XtQ8AMCfKLoBIABlLKbP5ciRI3K5XCpVqtQFL+OHH37QM888o2XLlun48eNe484suitUqHDW50uUKKFDhw5d8HKz48zluWOJioo6a/j5YggJCZF0/u/S7Y8//sj02cDuU+X/+OOPHBXd5cuXP+s61hIlSmjNmjUXPK+Mzvyu3EWh+3v5448/JElVq1Y967NVq1bVL7/8kq3lVKpUSePHj1d6erq2bdum559/XgcOHPC6e/aWLVtkZlkWs+7T3aOjo/Xggw/q9ddf1yeffKKWLVvquuuuU8+ePS/61PLzGTVqlLp166Zq1aqpdu3a6tixo+644w7VqVMnW5+389xDoHLlyrrjjjv03nvv6bHHHst0mhIlSmR5bfi53H///WrWrJl69OhxwZ/NjtKlSys+Pl5TpkzR8ePHlZaWphtuuCHL6Zs3b+6TOM5kZtm+BhwAAhFFNwAEoNDQUJUrV+68BdmaNWtUvnx5FSpUSJKy/GF65nWX27ZtU7t27VSjRg29/vrrioqKUqFChTR79my98cYbZz17Oatroc9XgJxPVteDZrW8zIafL4YaNWpIktauXavrr7/+wgI8h+x+126++g59Nd8zFS1a1KtQbN68ua666io9/vjjnqOh6enpcrlc+uabbzKNK+OR9tdee019+vTRV199pblz52rIkCEaPXq0li9fnukOCrfsXEN8Lq1atdK2bds8y33//ff1xhtv6N1331W/fv2y/FzJkiUlnd6ZUb58+XMuw31H/JdeeinTPpeSkqKDBw9mK97SpUsrf/78Wrhwob799ltNnz7d6+Z9qampOnHihHbu3Knw8HDPTqacuu2229S/f38lJCSoU6dOXtfrn+nAgQPZao9ixYqd9y7l53Lo0KEc7VgEgEDB3csBIEB17dpVO3bs0NKlSzMd//3332vnzp2eu4ZLp4+gHT58+Kxp3Uc73WbOnKnk5GT997//1d13363OnTsrPj7e65TzC3WuI1GZxZWSkqK9e/fmeHnZ1aJFC5UoUUKffvpptgqEihUrZvo87E2bNnnGS/87onxmXmd+1xfCF0fz3PFu3br1rHGZDcuuOnXqqGfPnvq///s/7dq1S5JUpUoVmZmio6MVHx9/1qtp06Ze84iNjdWTTz6pJUuW6Pvvv9dff/2ld999V9LFf7/n+i7Dw8N155136tNPP9Xu3btVp06dc94NXfrfzpsdO3acd9lVqlTxfDeZ9fEff/xRZcuWzdbLfdd393fcvXt3RUdHe15//fWXFi5cqOjoaH344Yfnje18/vWvfylfvnxavnz5ee9a3qhRo2zlcLHP2d6xY0eOb8oIAIGAI90AEKAefvhhTZ48WXfffbeWLFniOdImSQcPHtQ999yjkJAQDRo0yDO8SpUqSkxM1Jo1azyny+7du1dffvml17zdRyEzHg1NTEzUhAkTchxv0aJFJZ1dJLnjWrJkidew995776KPWmZHkSJFNGzYMD322GMaNmyYXnnllbMKso8//ljVqlVT48aN1blzZ40ZM0bLli1TXFycJOnYsWN67733VKlSJcXExHhykqQlS5aoXr16kk4fhX3vvfdyHOu5vsOcKleunGrXrq1JkyZp+PDhniOOixcv1tq1az1FeU48+uijmjRpkl5//XWNGTNG3bt31/DhwzVy5Eh9/PHHXt+zmengwYMqWbKkkpKSVKRIEa/nQcfGxipfvnxKTk6WdPqygFKlSmnJkiUaOnSoZ7rs3qm/aNGimX6P//zzj9e6VKxYMVWtWvWsR5qdqUGDBipUqJBWrlyp66677rzLd1/bnfGxcG45uaa7bdu2Z63HkjRgwABVrFhRTzzxhGJjY7M1z3MpVqyYxo0bp507d6pr167nnPZSXNOdmJiobdu26d57783xPADA3yi6ASBAVa1aVZMmTdKtt96q2NhY9e3bV9HR0dq5c6c++OADHTp0SFOnTlV0dLTnM7fccouGDRumf/3rXxoyZIiOHz+ucePGqVq1al7X7rZv316FChVS165ddffdd+vo0aMaP368ypQpk+Ojz/Xq1VP+/Pn10ksvKTExUUFBQZ7ngPfr10/33HOPevTooWuuuUa//fab5syZc8lOGX3kkUe0fv16vfbaa/ruu+90ww03KDIyUgkJCZoxY4Z+/vln/fjjj5Kkxx57zPPYpCFDhig8PFwfffSRduzYoS+++MLz+KZatWqpadOmGj58uA4ePKjw8HBNnTpVqampOY6zSpUqCgsL07vvvqvixYuraNGiatKkiVcb58QLL7ygbt26qXnz5rrzzjt16NAhvf3226pdu7aOHj2a4/nGxMSoc+fOev/99/XUU0+pSpUqeu655zR8+HDt3LlT119/vYoXL64dO3boyy+/1IABA/Twww9r4cKFGjRokG688UZVq1ZNqampmjx5svLnz+91vXK/fv304osvql+/fmrYsKGWLFmi33//PVuxNWjQQOPGjdNzzz2nqlWrqkyZMmrbtq1iYmLUpk0bNWjQQOHh4Vq5cqWmTZvmtfMqM8HBwWrfvr3mz5+vUaNGnXf57qPdH3300VnjcnJNd4UKFTK9t8LQoUMVERFx1mnsffr08fTbC30We+/evbM1XU6v6Z45c6Z+++03Sacfn7ZmzRo999xzkk7fnC/j9fXz58+Xmalbt245WhYABAQ/3TUdAJBNa9eutdtuu80iIyMtX758JsmCg4Nt/fr1mU4/d+5cq127thUqVMiqV69uH3/8caaPDPvvf/9rderUseDgYKtUqZK99NJL9uGHH571mKKsHknUunXrsx7JNH78eKtcubLlz5/f67FZaWlpNmzYMCtVqpQVKVLEOnToYFu3bs3ykWErVqzwmq87/gMHDngN7927txUtWvQ83+D/TJs2zdq3b2/h4eFWoEABK1u2rN188822aNEir+m2bdtmN9xwg4WFhVlwcLA1btzYZs2addb8tm3bZvHx8RYUFGQRERH2+OOP27x58zJ9ZFitWrXO+nxmj3j76quvLCYmxgoUKOD1yKysHhn2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bUNaWppSU1P1zDPPqEePHqpdu3ae/FHg5H7ntDZy4npEvwtcTux37kLu6NGj2r17t3r16qXbbrtN3bt3z5NtJP2vndwF6iuvvKKbb75Zbdq0yZOFt9PWo+wq4O8AELgy7oHKly+ffvnlF7355ptat26dChcurLi4OJ08eVJXXHGFnyPNvjNzWrdunf7v//5PP/zwgwoWLKgqVaooJSVFERERfo40e5yWj+S8nJyWj3R5bBs2b96sSZMm6euvv5bL5VLp0qXVvHlzlS5d2s+RZs/l0O+c1kZOXI/od4HH6f3u1KlT+vXXX/XSSy/pr7/+UkhIiLp3764TJ04oOjraz5Fm35nttH37dv3nP//R1KlTlZaWpoIFCyomJkbh4eF+jjR7nLYe5QRHupEl98rx4YcfaujQoWrRooUk6eGHH9b333+vn3/+Wa1bt1b16tX9GeYFcef02Wefafjw4WrUqJEOHjyogQMHavny5Vq/fr2uvvpqVahQwc+RZo/T8pGcl5PT8pGcvW2YNWuWRo4cqfr162vLli3q27evVqxYoV27dqlt27Z55geBk/ud09rIiesR/S5wObnfvfnmmxo8eLDi4+NVsmRJPfHEE5o3b54WL16sli1bql69ev4N9AK4c1q0aJFefvll1a9fX8uXL9dtt92mFStWKDExUW3btlVoaKifI80ep61HOWJAFlJSUmzChAlWuXJlu/fee2369OmecV999ZU1b97c9uzZY2ZmaWlp/grzgpw6dcpee+01i46Ott69e9vUqVM94z755BOLi4uzw4cPm5lZenq6v8LMtpSUFEflY+a8nJyWj5lztw1PPPGERUdHW48ePeyjjz7yjBs/frw1bdrUTp48aWZ5o52ctq0zc14bOXU9ot8FtuTkZEf2u5kzZ9qVV15pjzzyiH399deecfPnz7eWLVvali1bzCzv5JSWlmYDBw60KlWqWMeOHe29996zEydOmJnZG2+8YU2aNPFMmxf6ndPWo5zg9HKcxf7/KSAFCxZUmzZt1LFjR4WFhSk4ONgzzbRp01S+fHmFhYVJ+t/NKgJdgQIFFB8fr+7du6tkyZIqXry4Z9zMmTMVExPjydO9Vy6QudvIKflIzsvJSflcDtuGW265ReXKlfM6ZW/OnDmKi4vz5BLo7SQ5b1snOaeNLof1iH4XuAoVKqQWLVrohx9+yPP9zr0uFShQQM2aNdPPP/+s4sWLK3/+/J5ppkyZouLFiysyMlJS4Ofkli9fPrVv31533HGHKlas6IlfkhYvXqwOHTooLS1N+fLlyxP9rkCBAurQoYNj1qMc8W/Nj0Cye/duz16mc+0JnD59uoWGhtqaNWvMLLD3SP3zzz+eXM4V56effmrFixe3jRs3nndaf1q4cKGNGzfOXn31Vfv555+zjDOv5GPmvJyclo+ZM7cNP/zwg02bNs0mTZpku3fvznK6CRMmWNGiRW3r1q2XMLoL57RtnZnz2siJ6xH9LvD73TfffGMjR460Rx991L744ossv/u81O82bdpkR48eNbNzr0tff/21lSpVylasWGFmgZ3TqlWr7LvvvrOvv/7ac0Q7M+PGjbPixYvbH3/8cQmju3AZczjX955X1qPcQNENMzP7+OOPrXbt2vbxxx9bcnKymZ29kqSnp1taWpo98MADdt9991lKSkpAn6YzefJka9mypf34449ZrvDp6el24sQJGzBggD388MNmFrinHn3wwQdWrFgxa9++vYWHh1vdunWtT58+nnhTU1PzVD5mzsvJafmYOXPb8P7771tISIg1adLEChYsaI0aNbJnnnnGk5e7nZKSkqxnz5721FNPmVngtpPTtnVmzmsjJ65H9LvA73cTJkywwoUL280332zVq1e3WrVqWZs2bTwFkTufvNTvPv74Y7viiivs2WeftSNHjphZ1kXdk08+aX369LGkpKSALrjHjx9vJUuWtFq1apnL5bI2bdrYhx9+6BmflpZm6enpduDAAevevbuNHj3aMzwQTZo0ybp16+a5TCEzeWk9yi0U3bC5c+da+fLlrXz58ta4cWP77LPPsvxRkJCQYOXLl7cPPvjAH6Fm2zfffGNlypSx4OBgu+qqq855xHHHjh1Wrlw5r2vPAs327dstOjraJk6caGZmR48etX//+99Wp04da9eundeGKi/kY+a8nJyWj5kztw3r16+3K664wqZMmWInT560Q4cO2f33328NGjSwu+66yyuvdevWWbly5WzmzJl+jPjcnLatM3NeGzlxPaLfBX6/27t3r9WsWdPGjRtnZmYnT560mTNnWmxsrNWqVctzpNgs7/S7BQsWWHR0tNWtW9eaNWtmL774YpaF98GDB61SpUr25ptv+iPUbFuxYoWVKVPGPvvsM9u3b5/98ccfdt1111nTpk1t1KhRXnn99NNPVq5cOVuwYIEfIz63WbNmWUhIiLlcLmvfvr0lJCRkOW1eWI9yU964sAE+c+LECS1dulQdO3bUDz/8oDJlymj06NGaMWOGUlJS5HK5ZGZe0z///PO66667/Bj1uSUmJmrevHm69dZbtW3bNp06dUp33XWXVq5c6cklY05JSUl65JFHdPPNN/sr5PM6fPiwTpw4oSZNmkiSihYtqv79+2vkyJFKSEjQTTfd5MkpMTEx4PORnJeT0/Jx4rZBkvbt2yeXy6VWrVopKChIYWFhGjlypG6//Xb9+uuvevjhhz3THjx4UP369dO1117rx4iz5sRtneSsNnLiekS/C/x+J53uS4mJiapfv74kKSgoSJ06ddLkyZOVP39+tW3b1tNOx48fD/h+l5aWplWrVqlZs2b68ssvddVVV2natGkaO3asjh49KpfL5Xn+s3S6D44dO1aDBw/2vA9Eu3btUmhoqDp06KAyZcqoQoUK+uCDD9SoUSPNmjVLb731lmfa/fv364YbblDbtm39GHHWDhw4oBkzZuiuu+7Szz//rN9//1233nqr9u3bl+n0eWE9ylV+KPQRQNLT02316tX2/fffm9npU426dOli9erVs88++8xz/VlGx44d83w2EKWkpNicOXNs8eLFZnb6jom1a9e22rVr288//5zp6SvHjx83s8DNae/evValShV79913vYYnJyfbRx99ZHXr1rXJkyd7DTcL3HzMnJfTnj17rGrVqo7Jx4nbBjOz1atXW+XKle2bb74xs//FeuTIERsxYoQ1aNDAs+0wC+x2cuK2zsxZbeTE9SglJcXmzp1Lvwvgfmd2Or6aNWva8OHDzxq3ePFii4mJseeee85rerPAzcfs9O+GH374wcxOx3nfffdZw4YN7cUXX7SkpKSzpnf3u0D2zTffWHR0tK1bt87MTq9PZqfvl9C7d29r3ry51/XOKSkpZhaY7XT8+HGbPHmyZ3u3ZcsWq1ixol199dVZHvF2X+oQiPnkNoruy5i7g5/576lTp7x+FJw6dcoSExPt7bff9lusF8r9x8P9xz8lJcXzo8B9Q43Dhw/bZ5995rcYL8SxY8fshhtusA4dOtjatWu9xqWkpFirVq2sT58+foouZ5yWU1JSkvXo0cMR+Th523DgwAG76qqr7IYbbrB//vnHa9yxY8escuXK9uijj/opugvntG2dmfPayP0j2gnrUcYczJzV7/755x9r0KCBI/pdenq6paam2iOPPGItW7b0eoSWe/wdd9xhXbp0yRPFTlYxpqamehXex44dsyNHjnhdhx/o/vzzT4uIiLBBgwZ5hqWmppqZ2d9//22hoaH2yiuv+Cu8C3bmTeB+//13T+G9b98+MzM7dOiQLVy40B/h+RVF92XIvRc9M+4VPSUlxbp06WL169e38ePHW1xcnDVu3Dhgb3KwefNm++GHH2zLli2eZ4C6Y3X/OEhOTrbatWtbbGysffvttxYXF2edOnUKyA1zxjZy57Fp0yaLiIiw66+/3jZt2uQ1/fDhw61bt26e9gtETstp9erV9vXXX9v333/vuVnI+vXrLSIiwrp165bn8jFz9rZh69atdvDgQTMzW758uRUqVMjuvffes46O3HXXXXbXXXf5I9Rscdq2zsx5bZRx2+A+unNmsZrX1qPMjsi75dV+lzEn9/e+cuVKCwoKsvvuuy/P9bvExETP/93f+c6dO61p06bWvn17mzt3rtf0b7zxhrVq1SqgjwZnzOlM7r9Jp06dsoEDB1rjxo3tqaeesri4OKtSpUrA/q3dtWuXbdiwwQ4fPuz5mzt9+nTLnz+/15kH7ja89tprA3pnT8Z83AW3+8Zvbps3b7aKFSta27Ztbe3atda0aVO7/fbbA3bb4CsU3ZeZL774wvr162ebN2/OcpqMe7A7dOhgLpfL6tSpE7CntLz//vsWFRVl5cqVs0qVKlm7du08j7zIuBfe7PRG2n13yFq1agVkTpm1kbtNVq9ebWFhYda1a1f773//a6mpqXbo0CFr2bKl3Xvvvf4K+bycltP48eMtMjLSoqOjrWLFila1alWbN2+emeXNfMwuj21D27Zt7ZdffjEzsxkzZlihQoWsZ8+e9ttvv1l6erodP37cGjdubMOGDfNz5Jlz2rbOzHltlNm24bvvvvOaJq+tR1999ZU9//zz57whUl7rd5nl5C7SZs6caUFBQXmq33322WfWrl07r0djufPZtGmTXXXVVRYfH29vvfWWJScn2969e61du3Z2xx13+DPsczozp8y4c0xPT7e+ffuay+Wyq666ytPvAm0n1ocffmhVq1a1yMhIq1q1qtff3DFjxli+fPls2LBh9vfff5vZ6R1Z9evXtxdeeMGfYWcpYz5VqlSx/v372++//25m3m1jZrZ161arVKmSuVwuq1GjhqeNLicU3ZeRr776yvLnz29XXHGFDRkyxLZs2ZLltGlpaXb8+HFr0aKFNW3a1PMjwf1voFiyZIkVK1bMJk+ebNu3b7cpU6ZY165drVixYl7X0Jmdzik5OdmaN29uzZo1C8icsmqj9PR0T5zr1q2zFi1aWO3ate2KK66wBg0aWGxsbMBuwJyW008//WRhYWE2depUO3DggC1dutT69Olj+fPn9zziY82aNda8efM8kY/Z5bVtKFq0qOe6zEWLFnnap3bt2hYXF2e1atUKuFzMnLetM3NeG2W1bShQoIBNmjTJa9q8sh5Nnz7dXC6XlSxZ0l599VXP6aGZySv97lw5uQuEpUuXWvny5fNEv/v666+tWLFiVrlyZbv++utt5cqVZub9N3br1q12xx132JVXXmmhoaFWp04dq1evXsDuFMkqp8ykp6fbkSNHrEWLFta4ceOA7Xfz5s2zokWL2vjx42316tU2evRoa9u2rVWvXt1zPfekSZOsSJEi1rx5c2vbtq21bNnSYmJiAi4Xs8zzadeunVWvXt2zMzjj2QaHDh2yevXqWfPmzQO2jXyNovsysWfPHuvQoYM99thj9sorr1j9+vVt4MCB5/xxPWzYMCtVqpRnoxyIK8fkyZOtdevWXnszd+7caT179rTChQvbqlWrzOx/e30HDRpkERERAZnT+doo4x/Q/fv3248//mhjxoyxqVOnBuwGzIk5zZ492+rXr+916mFKSoo99thjVqBAAfvqq6/M7HTuP/zwQ8DnczluG4KDg+2nn34ys9OPM5oyZYo9/fTTNnbs2IBtJydt69yc1kbn2jYULFjQc12t+9TLQF+P/vjjD2vbtq2NGDHCHnnkEYuKirKXXnopy8I7L/S77OTkLhR27doV8P3uwIED1qVLFxs6dKhNnDjR4uPj7dprr8208E5KSrKdO3faxx9/bHPnzvU6PTuQnC+nzIwaNcpKlCgRsP3OzOy1116zbt26eQ1bunSpdenSxaKjo23jxo1mdvrMhOeee84GDx5so0aN8uQSaKfLZ5XPtdde65VPenq6nTx50vr27Wvly5cP6DbyNYruy0RKSop9+OGHtmjRIjMze/vtt8/74/rQoUMBu1F2+7//+z8rVqzYWdf9/PXXX3bjjTdaTEyM/fXXX2Z2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99yT7TbPON9Zs2bZ5s2b7YYbbrCKFSvaqVOnLDk52caMGWMhISG2d+9e27t3rx05ciTLfggAuDQougEAPvfTTz+ZJJs+ffo5p5s7d67lz5/fdu3a5Rm2fv16k2Q///yzmWW/6G7RooXXNI0aNbJhw4Z53mdWcGVWdFesWNFSU1M9w2688Ua7+eabzcxs48aNJslWrFjhGb9lyxaTdN6iO1++fFa0aFELDg42SSbJXn/9dc80VapUsSlTpnh97tlnn7W4uDgzMxs3bpyVLFnSTpw44Rk/fvz4cxbdsbGxNmLEiExjOnNaM7OTJ09akSJF7Mcff/Satm/fvnbrrbd6fW7GjBlZ5uvm/s7HjBljV199tZmZjRw50v71r3/ZoUOHvIruyZMnW/Xq1S09Pd3z+eTkZCtcuLDNmTMn0/mnpaVZ8eLFbebMmWZm9tprr1m1atUsJSXlnPFklFnRPWbMGK9pztc27s+9//77nvGffvqpSbIFCxZ4ho0ePdqqV69+UfN1rx8bN240M7MJEyZYaGhopvkCAPyDa7oBAD5nZtmabuPGjYqKilJUVJRnWExMjMLCwrRx40Y1atQo28usU6eO1/uyZctq//792f68W61atZQ/f36v+axdu1aStHnzZhUoUEBXXXWVZ3zVqlVVokSJ8863evXq+u9//6uTJ0/q448/1urVqzV48GBJ0rFjx7Rt2zb17dtX/fv393wmNTXVc1O0zZs3q06dOgoODvaMb9y48TmXOWTIEN17772aO3eu4uPj1aNHj7O+p4y2bt2q48eP65prrvEanpKSovr163sNa9iw4XlzduvZs6cee+wxbd++XRMnTtSbb7551jS//fabtm7dquLFi3sNP3nypLZt2yZJ2rdvn5588kktWrRI+/fvV1pamo4fP65du3ZJkm688UaNGTNGlStXVseOHdW5c2d17do1y+vNs5Ixt+y0jVvG7zYiIkKSFBsb6zXM3SdzOt+yZctKkvbv368aNWpcUF4AgEuDohsA4HNXXnmlXC5XrtwsLV++fGcV8RmvsXY782ZXLpdL6enpF7y83JrPmQoVKqSqVatKkl588UV16dJFI0eO1LPPPqujR49KksaPH68mTZp4fS7jDoAL1a9fP3Xo0EFff/215s6dq9GjR+u1117zFPtncsfx9ddf64orrvAaFxQU5PW+aNGi2Y6jZMmSuvbaa9W3b1+dPHlSnTp10pEjR85adoMGDTzXUGdUunRpSaevD//nn3/073//WxUrVlRQUJDi4uKUkpIi6fRN2zZv3qz58+dr3rx5uu+++/TKK69o8eLFKliwoFwuV7b6UsbcLqRtMvYdl8uV6TB3X7rY+eZGnwQA+AY3UgMA+Fx4eLg6dOigsWPH6tixY2eNd9/oq2bNmtq9e7d2797tGbdhwwYdPnxYMTExkk4XXHv37vX6vPvGYReiYMGCSktLu+DPZVS9enWlpqbq119/9QzbunWrDh06dMHzevLJJ/Xqq69qz549ioiIULly5bR9+3ZVrVrV6xUdHe1Z9tq1a5WcnOyZx4oVK867nKioKN1zzz2aPn26HnroIY0fP17S6Z0Akry+k5iYGAUFBWnXrl1nxZHxbIScuOuuu7Ro0SL16tUr0x0JV111lbZs2aIyZcqctWz3kd8ffvhBQ4YMUefOnVWrVi0FBQXp77//9ppP4cKF1bVrV7355ptatGiRli1b5jlT4cy+tGXLFh0/fvyccWenbXIit+ZbqFChi+7XAIDcRdENALgkxo4dq7S0NDVu3FhffPGFtmzZoo0bN+rNN99UXFycJCk+Pl6xsbG6/fbb9csvv+jnn39Wr1691Lp1a88pvm3bttXKlSs1adIkbdmyRc8884zWrVt3wfFUqlRJCxYsUEJCQo6KZEmqUaOG4uPjNWDAAP3888/69ddfNWDAABUuXNhzBDK74uLiVKdOHb3wwguSpJEjR2r06NF688039fvvv2vt2rWaMGGCXn/9dUnSbbfdpvT0dA0YMEAbN27UnDlz9Oqrr0pSlsseOnSo5syZox07duiXX37Rd999p5o1a0qSKlasKJfLpVmzZunAgQM6evSoihcvrocfflgPPPCAPvroI23btk2//PKL3nrrLX300Uc5+s7cOnbsqAMHDmjUqFGZjr/99ttVqlQpdevWTd9//7127NihRYsWaciQIfrzzz8lnT6DYvLkydq4caN++ukn3X777SpcuLBnHhMnTtQHH3ygdevWafv27fr4449VuHBhVaxYUdLpvvT222/r119/1cqVK3XPPfdk63Fg52ubnMqN+VaqVElHjx7VggUL9Pfff593JwIAwPcougEAl0TlypX1yy+/6Oqrr9ZDDz2k2rVr65prrtGCBQs0btw4SaeLxa+++kolSpRQq1atFB8fr8qVK3s9u7pDhw566qmn9Oijj6pRo0Y6cuSIevXqdcHxvPbaa5o3b56ioqLOuj75QkyaNEkRERFq1aqV/vWvf6l///4qXry417XW2fXAAw/o/fff1+7du9WvXz+9//77mjBhgmJjY9W6dWtNnDjRc9QzJCREM2fO1OrVq1WvXj098cQTevrppyUpy2WnpaVp4MCBqlmzpjp27Khq1ap5Hkl1xRVXaOTIkXrssccUERGhQYMGSZKeffZZPfXUUxo9erTnc19//fVFHdWVTrd1qVKlPEfYz1SkSBEtWbJEFSpUUPfu3VWzZk3P6eghISGSpA8++ECHDh3SVVddpTvuuENDhgxRmTJlPPMICwvT+PHj1bx5c9WpU0fz58/XzJkzVbJkSUmn+0BUVJRatmyp2267TQ8//LCKFCly3tjP1zY5lRvzbdasme655x7dfPPNKl26tF5++eWLigkAcPFclt272wAAgPP6888/FRUVpfnz56tdu3aXdNmffPKJ5znNGY/4AgAA/+FGagAAXISFCxfq6NGjio2N1d69e/Xoo4+qUqVKatWqlc+XPWnSJFWuXFlXXHGFfvvtNw0bNkw33XQTBTcAAAGEohsAgItw6tQpPf7449q+fbuKFy+uZs2a6ZNPPsnWtcEXKyEhQU8//bQSEhJUtmxZ3XjjjXr++ed9vlwAAJB9nF4OAAAAAICPcCM1AAAAAAB8hKIbAAAAAAAfoegGAAAAAMBHKLoBAAAAAPARim4AAAAAAHyEohsAAAAAAB+h6AYAAAAAwEcougEAAAAA8BGKbgAAAAAAfOT/AfsbXIsOtbMKAAAAAElFTkSuQmCC", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAHqCAYAAAAZLi26AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAbzlJREFUeJzt3Xd4FGX3//HP0kJNQigJSAsgJRCK1NBLpCs+YBcBpVgoYkWsgAW7WBC+ooKgiI+IKFjoRRQUUKQjVVAIoEBCTUhyfn/w232yJIEQsuxmfL+uKxfszOzMOXvf9yRnp7nMzAQAAAAAAHJcHn8HAAAAAACAU1F0AwAAAADgIxTdAAAAAAD4CEU3AAAAAAA+QtENAAAAAICPUHQDAAAAAOAjFN0AAAAAAPgIRTcAAAAAAD5C0Q0AAAAAgI9QdAMAkAv07dtXlSpV8ncYAWny5MlyuVzavXu3z7f13//+V2FhYTp+/LjPt/Vv9+ijj6pJkyb+DgMALhlFNwAEuI0bN6pXr1664oorFBQUpLJly6pXr17atGmTv0PzsmnTJo0cOfKyFD7Z9cUXX6hz584qWbKkChQooLJly+rGG2/UokWL/B2aJGnfvn0aOXKk1q5d6+9QvLRp00Yul8vzU6hQIdWpU0djx45Vamqqv8PL0DvvvKPJkyfn6DpTUlL09NNPa8iQISpatKhneqVKleRyuTRkyJB071myZIlcLpdmzJiRo7FI0oABA+RyudStW7dsr8P9hYXL5dLy5cvTzTczlS9f/pK3k9b48eN1ww03qEKFCnK5XOrbt2+Gyw0bNky//fabvvrqqxzZLgD4C0U3AASwmTNn6qqrrtLChQt1xx136J133lG/fv20aNEiXXXVVfryyy/9HaLHpk2bNGrUqIAsus1Md9xxh3r06KEDBw7ogQce0IQJEzRo0CDt3LlT7du3148//ujvMLVv3z6NGjUqw6J74sSJ2rp16+UP6v8rV66cpk6dqqlTp2rMmDEqWLCg7r//fj355JN+i+l8fFF0z549W1u3btXAgQMznD9x4kTt27cvR7eZmdWrV2vy5MkqWLBgjqyvYMGCmjZtWrrpS5cu1Z9//qmgoKAc2Y4kvfjii1q0aJFq1aqlfPnyZbpcRESEunfvrldeeSXHtg0A/pD5ng4A4Fc7duzQ7bffrsqVK2vZsmUqVaqUZ959992nli1bqlevXlq3bp0iIyP9GGnge/XVVzV58mQNGzZMr732mlwul2fe448/rqlTp573j/9AkD9/fr9uPyQkRL169fK8vvvuu1WjRg299dZbGj16tPLmzevH6C6PSZMmqXnz5rriiivSzatVq5a2bt2qF154QW+++aZP4zAzDR06VL1799bChQtzZJ1dunTRZ599pjfffNNrLEybNk0NGjTQ33//nSPbkc4W8u6j3GnPGMjIjTfeqBtuuEE7d+5U5cqVcywGALicONINAAHq5Zdf1smTJ/Xuu+96FdySVLJkSf3f//2fjh8/rpdfftkzPbPrfkeOHOlVaEpnC4h27dqpdOnSCgoKUlRUlMaPH5/uvZUqVVK3bt20fPlyNW7cWAULFlTlypU1ZcoUzzKTJ0/WDTfcIElq27at53TVJUuWSJJcLpdGjhyZ4brTnlrqPtV1+fLlGjp0qEqVKqXQ0FDdddddSkpK0tGjR9W7d28VL15cxYsX1yOPPCIzO+/neOrUKY0ZM0Y1atTQK6+8ku5zkKTbb79djRs39rzeuXOnbrjhBoWFhalw4cJq2rSpvv76a6/3ZHYdsft0Ynfu0tnTs2vXrq1Nmzapbdu2Kly4sK644gq99NJLXu9r1KiRJOmOO+7wfIbuo7Xntu3u3bvlcrn0yiuv6N1331WVKlUUFBSkRo0aadWqVely/OyzzxQVFaWCBQuqdu3a+uKLLy7pOvGCBQuqUaNGOnbsmA4ePOg176OPPlKDBg1UqFAhhYWF6eabb9bevXu9ltm2bZt69uypiIgIFSxYUOXKldPNN9+s+Ph4r/wyOlqdWX9yq1SpkjZu3KilS5d6Psc2bdpIks6cOaNRo0bpyiuvVMGCBVWiRAm1aNFC8+fPP2++p0+f1nfffafY2NhMt9m7d+/LcrR76tSp2rBhg5577rkcW+ctt9yif/75x+tzSEpK0owZM3Trrbfm2HYkqWLFihmOw4y4P+9AOqsHAC5WYH+tDwD/YrNnz1alSpXUsmXLDOe3atVKlSpV0uzZs/XOO+9c9PrHjx+vWrVq6dprr1W+fPk0e/Zs3XvvvUpNTdWgQYO8lt2+fbuuv/569evXT3369NEHH3ygvn37qkGDBqpVq5ZatWqloUOH6s0339Rjjz2mmjVrSpLn34s1ZMgQRUREaNSoUVq5cqXeffddhYaG6scff1SFChX0/PPP65tvvtHLL7+s2rVrq3fv3pmua/ny5Tp8+LCGDRuWpaOxBw4cULNmzXTy5EkNHTpUJUqU0Icffqhrr71WM2bM0H/+859s5XTkyBF16tRJPXr00I033qgZM2Zo+PDhio6OVufOnVWzZk2NHj1aTz31lAYOHOhp92bNmp13vdOmTdOxY8d01113yeVy6aWXXlKPHj20c+dOz9Hxr7/+WjfddJOio6M1ZswYHTlyRP369cvwiO3FcBfGoaGhnmnPPfecnnzySd14443q37+/Dh06pLfeekutWrXSr7/+qtDQUCUlJaljx45KTEz0tPVff/2lOXPm6OjRowoJCbmkuMaOHeu57vrxxx+XJIWHh0s6+wXUmDFj1L9/fzVu3FgJCQlavXq1fvnlF1199dWZrnPNmjVKSkrSVVddlekyjz/+uKZMmXLBo91nzpzxfLlwIWFhYcqT53/HSI4dO6bhw4frscceU0RERJbWkRWVKlVSTEyMPvnkE3Xu3FmS9O233yo+Pl4333xzhvkcOXJEKSkpF1x34cKFVbhw4WzFFRISoipVquiHH37Q/fffn611AIDfGQAg4Bw9etQkWffu3c+73LXXXmuSLCEhwczM+vTpYxUrVky33NNPP23n7vJPnjyZbrmOHTta5cqVvaZVrFjRJNmyZcs80w4ePGhBQUH24IMPeqZ99tlnJskWL16cbr2S7Omnn043vWLFitanTx/P60mTJpkk69ixo6Wmpnqmx8TEmMvlsrvvvtszLTk52cqVK2etW7dOt9603njjDZNkX3zxxXmXcxs2bJhJsu+//94z7dixYxYZGWmVKlWylJQUr1h37drl9f7Fixen+xxat25tkmzKlCmeaYmJiRYREWE9e/b0TFu1apVJskmTJqWL69y23bVrl0myEiVK2OHDhz3Tv/zyS5Nks2fP9kyLjo62cuXK2bFjxzzTlixZYpIy7C/nat26tdWoUcMOHTpkhw4dsi1bttjDDz9skqxr166e5Xbv3m158+a15557zuv969evt3z58nmm//rrrybJPvvss0y36c4vo8/i3P6UUVvUqlUrw75Rt25dr5iz6r333jNJtn79+nTzKlas6FnnHXfcYQULFrR9+/aZ2f/6Q9pc3dOy8nNu/3rooYcsMjLSTp8+nW7b2eH+7FatWmVvv/22FStWzLNvuOGGG6xt27aZbse9b7jQT0Zj361IkSJe+4CMdOjQwWrWrJntHAHA3zjSDQAB6NixY5KkYsWKnXc59/xjx45dcNlzFSpUyPP/+Ph4nTlzRq1bt9bcuXMVHx/vdbQxKirK64h7qVKlVL16de3cufOitplV/fr18zr9tEmTJlqxYoX69evnmZY3b141bNhQa9asOe+6EhISJF34s3T75ptv1LhxY7Vo0cIzrWjRoho4cKBGjBihTZs2qXbt2heTjmcdaa+JLlCggBo3bnzJn+FNN92k4sWLe16728m93n379mn9+vV67LHHvK6fbd26taKjoz2fz4Vs2bIl3WUO1157rd5//33P65kzZyo1NVU33nij1zXAERERuvLKK7V48WI99thjnr41d+5cdenSJdtHQbMjNDRUGzdu1LZt23TllVdm+X3//POPJHl91hl54oknNHXqVL3wwgt64403Mlymbt26Fzyd3S3t0ezff/9db7zxhj755JMcvbGZ24033qhhw4Zpzpw56tSpk+bMmXPeI/Yff/yxTp06dcH1Xuq12MWLF9evv/56SesAAH+i6AaAAJS2mD6fY8eOyeVyqWTJkhe9jR9++EFPP/20VqxYoZMnT3rNO7forlChQrr3Fy9eXEeOHLno7WbFudtzx1K+fPl00y8UQ3BwsKQLf5Zuf/zxR4bPBnafKv/HH39kq+guV65cuutYixcvrnXr1l30utI697NyF4Xuz+WPP/6QJFWtWjXde6tWrapffvklS9upVKmSJk6cqNTUVO3YsUPPPfecDh065HX37G3btsnMMi1m3ae7R0ZG6oEHHtBrr72mjz/+WC1bttS1116rXr16XfKp5RcyevRode/eXdWqVVPt2rXVqVMn3X777apTp06W3m8XuIdA5cqVdfvtt+vdd9/Vo48+muEyxYsXz/Ta8PO577771KxZM/Xs2fOi35sVpUqVUmxsrKZNm6aTJ08qJSVF119/fabLN2/e3CdxnMvMsnwNOAAEIopuAAhAISEhKlu27AULsnXr1qlcuXIqUKCAJGX6h+m5113u2LFD7du3V40aNfTaa6+pfPnyKlCggL755hu9/vrr6Z69nNm10BcqQC4ks+tBM9teRtMvFEONGjUkSevXr9d11113cQGeR1Y/azdffYa+Wu+5ihQp4lUoNm/eXFdddZUee+wxz9HQ1NRUuVwuffvttxnGlfZI+6uvvqq+ffvqyy+/1Lx58zR06FCNGTNGK1euzPALCresXEN8Pq1atdKOHTs8233vvff0+uuva8KECerfv3+m7ytRooSks19mlCtX7rzbcN8R/8UXX8ywzyUlJenw4cNZirdUqVLKmzevFi1apO+++04zZ870unlfcnKyTp06pd27dyssLMzzJVN23XrrrRowYIDi4uLUuXNnr+v1z3Xo0KEstUfRokUveJfy8zly5Ei2vlgEgEDB3csBIEBdc8012rVrl5YvX57h/O+//167d+/23DVcOnsE7ejRo+mWdR/tdJs9e7YSExP11Vdf6a677lKXLl0UGxvrdcr5xTrfkaiM4kpKStL+/fuzvb2satGihYoXL65PPvkkSwVCxYoVM3we9pYtWzzzpf8dUT43r3M/64vhi6N57ni3b9+ebl5G07KqTp066tWrl/7v//5Pe/bskSRVqVJFZqbIyEjFxsam+2natKnXOqKjo/XEE09o2bJl+v777/XXX39pwoQJki798z3fZxkWFqY77rhDn3zyifbu3as6deqc927o0v++vNm1a9cFt12lShXPZ5NRH//xxx9VpkyZLP247/ru/ox79OihyMhIz89ff/2lRYsWKTIyUh988MEFY7uQ//znP8qTJ49Wrlx5wbuWN2rUKEs5XOpztnft2pXtmzICQCDgSDcABKiHHnpIU6dO1V133aVly5Z5jrRJ0uHDh3X33XcrODhYgwcP9kyvUqWK4uPjtW7dOs/psvv379cXX3zhtW73Uci0R0Pj4+M1adKkbMdbpEgRSemLJHdcy5Yt85r27rvvXvJRy6woXLiwhg8frkcffVTDhw/Xyy+/nK4g++ijj1StWjU1btxYXbp00dixY7VixQrFxMRIkk6cOKF3331XlSpVUlRUlCcnSVq2bJnq1asn6exR2HfffTfbsZ7vM8yusmXLqnbt2poyZYpGjBjhOeK4dOlSrV+/3lOUZ8cjjzyiKVOm6LXXXtPYsWPVo0cPjRgxQqNGjdJHH33k9TmbmQ4fPqwSJUooISFBhQsX9noedHR0tPLkyaPExERJZy8LKFmypJYtW6Zhw4Z5lsvqnfqLFCmS4ef4zz//eI2lokWLqmrVqukeaXauBg0aqECBAlq9erWuvfbaC27ffW132sfCuWXnmu527dqlG8eSNHDgQFWsWFGPP/64oqOjs7TO8ylatKjGjx+v3bt365prrjnvspfjmu74+Hjt2LFD99xzT7bXAQD+RtENAAGqatWqmjJlim655RZFR0erX79+ioyM1O7du/X+++/ryJEjmj59uiIjIz3vufnmmzV8+HD95z//0dChQ3Xy5EmNHz9e1apV87p2t0OHDipQoICuueYa3XXXXTp+/LgmTpyo0qVLZ/voc7169ZQ3b169+OKLio+PV1BQkOc54P3799fdd9+tnj176uqrr9Zvv/2muXPnXrZTRh9++GFt3LhRr776qhYvXqzrr79eERERiouL06xZs/Tzzz/rxx9/lCQ9+uijnscmDR06VGFhYfrwww+1a9cuff75557HN9WqVUtNmzbViBEjdPjwYYWFhWn69OlKTk7OdpxVqlRRaGioJkyYoGLFiqlIkSJq0qSJVxtnx/PPP6/u3burefPmuuOOO3TkyBG9/fbbql27to4fP57t9UZFRalLly5677339OSTT6pKlSp69tlnNWLECO3evVvXXXedihUrpl27dumLL77QwIED9dBDD2nRokUaPHiwbrjhBlWrVk3JycmaOnWq8ubN63W9cv/+/fXCCy+of//+atiwoZYtW6bff/89S7E1aNBA48eP17PPPquqVauqdOnSateunaKiotSmTRs1aNBAYWFhWr16tWbMmOH15VVGChYsqA4dOmjBggUaPXr0BbfvPtr94YcfppuXnWu6K1SokOG9FYYNG6bw8PB0p7H37dvX028v9lnsffr0ydJy2b2me/bs2frtt98knX182rp16/Tss89KOntzvrTX1y9YsEBmpu7du2drWwAQEPx013QAQBatX7/ebr31VouIiLA8efKYJCtYsKBt3Lgxw+XnzZtntWvXtgIFClj16tXto48+yvCRYV999ZXVqVPHChYsaJUqVbIXX3zRPvjgg3SPKcrskUStW7dO90imiRMnWuXKlS1v3rxej81KSUmx4cOHW8mSJa1w4cLWsWNH2759e6aPDFu1apXXet3xHzp0yGt6nz59rEiRIhf4BP9nxowZ1qFDBwsLC7N8+fJZmTJl7KabbrIlS5Z4Lbdjxw67/vrrLTQ01AoWLGiNGze2OXPmpFvfjh07LDY21oKCgiw8PNwee+wxmz9/foaPDKtVq1a692f0iLcvv/zSoqKiLF++fF6PzMrskWEvv/xy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AAAA4CMU3QAAAAAA+AhFNwAAAAAAPkLRDQAAAACAj1B0AwAAAADgIxTdAAAAAAD4CEU3AAAAAAA+QtENAAAAAICP+LXoHj9+vOrUqaPg4GAFBwcrJiZG3377rWf+6dOnNWjQIJUoUUJFixZVz549deDAAa917NmzR127dlXhwoVVunRpPfzww0pOTr7cqQAAAAAAkI5fi+5y5crphRde0Jo1a7R69Wq1a9dO3bt318aNGyVJ999/v2bPnq3PPvtMS5cu1b59+9SjRw/P+1NSUtS1a1clJSXpxx9/1IcffqjJkyfrqaee8ldKAAAAAAB45PPnxq+55hqv188995zGjx+vlStXqly5cnr//fc1bdo0tWvXTpI0adIk1axZUytXrlTTpk01b948bdq0SQsWLFB4eLjq1aunZ555RsOHD9fIkSNVoEABf6QFAAAAAICkALqmOyUlRdOnT9eJEycUExOjNWvW6MyZM4qNjfUsU6NGDVWoUEErVqyQJK1YsULR0dEKDw/3LNOxY0clJCR4jpYDAAAAAOAvfj3SLUnr169XTEyMTp8+raJFi+qLL75QVFSU1q5dqwIFCig0NNRr+fDwcMXFxUmS4uLivApu93z3vMwkJiYqMTHR8zohISGHsgEAAAAA4H/8fqS7evXqWrt2rX766Sfdc8896tOnjzZt2uTTbY4ZM0YhISGen/Lly/t0ewAAAACAfye/F90FChRQ1apV1aBBA40ZM0Z169bVG2+8oYiICCUlJeno0aNeyx84cEARERGSpIiIiHR3M3e/di+TkREjRig+Pt7zs3fv3pxNCgAAAAAABUDRfa7U1FQlJiaqQYMGyp8/vxYuXOiZt3XrVu3Zs0cxMTGSpJiYGK1fv14HDx70LDN//nwFBwcrKioq020EBQV5HlPm/gEAAAAAIKf59ZruESNGqHPnzqpQoYKOHTumadOmacmSJZo7d65CQkLUr18/PfDAAwoLC1NwcLCGDBmimJgYNW3aVJLUoUMHRUVF6fbbb9dLL72kuLg4PfHEExo0aJCCgoL8mRoAAAAAAP4tug8ePKjevXtr//79CgkJUZ06dTR37lxdffXVkqTXX39defLkUc+ePZWYmKiOHTvqnXfe8bw/b968mjNnju655x7FxMSoSJEi6tOnj0aPHu2vlAAAAAAA8PBr0f3++++fd37BggU1btw4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Tvkd65aammrJycn28MMPW8uWLb0ez+Sef/vtt1vXrl1z1R/S//zzjzVo0MAxY+nPP/+08PBwGzx4sGdacnKymZn9/fffFhISYi+//LK/wrsomfWj5ORkr8L7xIkTduzYMa/r8ANR2n2bmXP2DWaW7mZ9v//+u6fwPnDggJmZHTlyxBYtWuSP8PyKovtfaOvWrfbDDz/Ytm3bPM/5cw949w4gMTHRateubdHR0fbdd99ZTEyMde7cOSB3Yu6jHBlx/4JJSkqyrl27Wv369W3ixIkWExNjjRs3DtibNqTNyR3jli1bLDw83K677jrbsmWL1/IjRoyw7t27e/INRE7LyT2Otm/fbocPHzYzs5UrV1qBAgXsnnvuSfet+5133ml33nmnP0LNMieOpbVr19rXX39t33//veemLhs3brTw8HDr3r07/S4ApG0j99GQc/8ozU39zmm/Y83M4uPjPf93x7h7925r2rSpdejQwebNm+e1/Ouvv26tWrUK6CONac+acLfP6tWrLSgoyO69995cN5b27NljmzZtsqNHj3r25TNnzrS8efN6nXXgbr9u3boF/JcIafvdudz76DNnztigQYOscePG9uSTT1pMTIxVqVIlIPfhGZ2p45Zb9w1p+5274HbfoM9t69atVrFiRWvXrp2tX7/emjZtarfddlvA5uQrFN3/Mu+9956VL1/eypYta5UqVbL27dt7HuGR9ps2s7M7NPcdL2vVqhWQpx59/vnn1r9/f9u6dWumy6T9JrFjx47mcrmsTp06AZmPWcY5uXNYu3athYaG2jXXXGNfffWVJScn25EjR6xly5Z2zz33+CvkC3JaTueOo3bt2tkvv/xiZmazZs2yAgUKWK9evey3336z1NRUO3nypDVu3NiGDx/u58gz58SxNHHiRIuIiLDIyEirWLGiVa1a1ebPn29m9LtAkVEbLV682GuZ3NTvnPY71szs008/tfbt23s9dsld0GzZssWuuuoqi42NtbfeessSExNt//791r59e7v99tv9GfZ5ffnll/bcc895nfLqzmn27NkWFBSUq8bSBx98YFWrVrWIiAirWrWq17587NixlidPHhs+fLj9/fffZna2sKtfv749//zz/gz7vM7tdxlxt1lqaqr169fPXC6XXXXVVZ6xFEhfymXU586V2/YNaftdlSpVbMCAAfb777+bmXfbmJlt377dKlWqZC6Xy2rUqOHJ6d+EovtfZNmyZVa0aFGbOnWq7dy506ZNm2bXXHONFS1a1Ov6ObOzO6rExERr3ry5NWvWzPNHj/vfQPDll19a3rx57YorrrChQ4fatm3bMl02JSXFTp48aS1atLCmTZsGZD5mmeeUmprqiXXDhg3WokULq127tl1xxRXWoEEDi46ODtgdmNNyymwcFSlSxHNt1pIlSzx51K5d22JiYqxWrVoB19/cnDiWfvrpJwsNDbXp06fboUOHbPny5da3b1/Lmzev55E569ats+bNm9Pv/CSzNsqXL59NmTLFa9nc0O+c9jvW7OxzjosWLWqVK1e26667zlavXm1m3vvv7du32+23325XXnmlhYSEWJ06daxevXoBWyjMnDnTXC6XlShRwl555RXPKa9m/4t1+fLlVq5cuVwxlubPn29FihSxiRMn2tq1a23MmDHWrl07q169uud67ilTpljhwoWtefPm1q5dO2vZsqVFRUUFZD5mmfe7jKSmptqxY8esRYsW1rhx44AcS+frc+fKLfuGjPpd+/btrXr16p4vGtOebXDkyBGrV6+eNW/ePGBz8jWK7n+RqVOnWuvWrb2++du9e7f16tXLChUqZGvWrDGz/32LPXjwYAsPD/f84gykwbFv3z7r2LGjPfroo/byyy9b/fr1bdCgQectFoYPH24lS5YMyHzMLpxT2j9yDh48aD/++KONHTvWpk+fHrA7MCfmdL5xVLBgQfvpp5/M7OzjPaZNm2ZPPfWUjRs3LmDzceJYMjP75ptvrH79+l6niCYlJdmjjz5q+fLlsy+//NLMzub/ww8/0O/84HxtlD9/fs+1wu5TFQO93znpd6zZ2fsFdO3a1YYNG2aTJ0+22NhY69atW4aFd0JCgu3evds++ugjmzdvntepv4Hkjz/+sHbt2tnIkSPt4YcftvLly9uLL77oVQS5Y9+zZ0+uGEuvvvqqde/e3Wva8uXLrWvXrhYZGWmbN282s7NnJTz77LM2ZMgQGz16tCePQDsN+0L9LiOjR4+24sWLB+RYykqfSys37BvMMu933bp18+p3qampdvr0aevXr5+VK1cuoHPyNYruf5H/+7//s6JFi6a7Ruavv/6yG264waKiouyvv/4ys7ODZNOmTQH7izMpKck++OADW7JkiZmZvf322xcsFo4cORKw+Zhl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BQV53fXVPZCnTp1qYWFhnuefphXIg90JOWWn36W9sZBboOTkxHHktDZKy52T+3Res7N3vM7oD7f4+Ph0XygEqqzsG8732JxAQhsFvotpo4SEhHRtFEj7hnNje+edd6xMmTKeRzW5paSk2HPPPWdRUVHp7n5tFjg5ZSefjO4iH4jjyin9zml9zszZ/c7f8gi5XmpqqiTJ5XJJkkqVKiUzU2pqqurVq6fhw4erXLlymjBhgj755BOdPHlSrVu31syZM/0Z9nklJyd7/t+iRQvdcMMNeu655/TDDz9IkvLmzStJql+/vvLly6ejR4+mW0e+fPkuS6xZ5bScstPvWrVqla7fBUpOThxHTmsjt+TkZE9OISEhks7mGhkZqXvuuUfdu3fXxIkT9frrrysxMVGxsbGaOHGiP0M+r4vdN8THx/slzotBGzmvjdq3b5+ujQJp3+De37k1a9ZMtWvX1ttvv62NGzd6pufJk0cxMTH666+/Avr3bHbyyajfuds4UDip3zmtz0nO7XcBwb81Py7VjBkz7KabbrLu3bvbsGHD7PDhw55vl9KelrN27Vq79dZbLSYmxipXrmwVK1YMyLsk/vDDD57/p/3mb968edapUydr06aNLViwwDP98OHDFhUVleGzTwOFE3NyWr9zWj5mzswp7Vg633Viu3fvtkcffdSqVatmZcqUsUqVKgVkTk7cN9BGtJE/pN3fpb0L/qeffmr169e33r1726pVqzzL//HHH1a7dm1buXKlv0I+L6flY+a8fufENnJiToGEojsX++ijjywoKMiGDh1qAwYMsAoVKli1atVs1qxZnseUpP3jeuHChZY/f/6AvRPxJ598Yi6Xy1q2bOkpDtLeZOebb76xnj17WunSpe2pp56ycePG2dVXX23169cP2Bs1ODEnp/U7p+Vj5sycMhpL54tx1apVFhISYjExMQGZkxP3DbQRbeQPGe3vqlatarNnzzYzs2nTplnLli2tXr169vbbb9vMmTPt6quvtsaNG6e7ZjgQOC0fM+f1Oye2kRNzCjQU3blQcnKyJSQkWKtWreyFF17wmt6xY0erUaOG/fe///XaQf3999/WsmVLi46ODsgd2MqVK61OnTrWq1cvi46OtjZt2mT4R86WLVvs1VdftSpVqlibNm2sZ8+eAXuHRKfl5LR+57R8zJyZk9n5x1JGsR45csQ6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SpUqSZL+85//yOVyeV6fe3q5e1uvvPKKypQpoxIlSmjQoEE6c+aMZ5n9+/era9euKlSokCIjIzVt2jRVqlRJY8eOPe/nkS9fPkVEROiKK65QbGysbrjhBs2fP99rmffee081a9ZUwYIFVaNGDb3zzjte83/88UfVq1dPBQsWVMOGDTVr1iy5XC6tXbtWUvqj13/88YeuueYaFS9eXEWKFFGtWrX0zTffaPfu3Wrbtq0kqXjx4nK5XOrbt68kKTU1VWPGjFFkZKQKFSqkunXrasaMGZ4Y3Nv49ttv1aBBAwUFBWn58uWZ5t2nTx9Nnz5dp06d8kz74IMP1KdPn3TL7t27VzfeeKNCQ0MVFham7t27a/fu3Z75q1at0tVXX62SJUsqJCRErVu31i+//OKZb2YaOXKkKlSooKCgIJUtW1ZDhw71zM/obIfQ0FBNnjxZ0tkvilwulz799FO1bt1aBQsW1Mcff3zBtnG/77///a9atmypQoUKqVGjRvr999+1atUqNWzYUEWLFlXnzp116NAhr+1nZb0zZ85U27ZtVbhwYdWtW1crVqzwtMUdd9yh+Ph4z1kFafs9AMBPDAAAH/vnn3/M5XLZ888/f97lUlJSrF69etaiRQtbvXq1rVy50ho0aGCtW7f2LNOnTx/r3r271/vuu+8+r2Vat25twcHBNnLkSPv999/tww8/NJfLZfPmzTMzs4MHD5okmzRpku3fv98OHjxoZmZPP/201a1b12tbwcHBdvfdd9vmzZtt9uzZVrhwYXv33Xc9y8TGxlq9evVs5cqVtmbNGmvdurUVKlTIXn/99UzzPHc7u3btslq1all4eLhn2kcffWRlypSxzz//3Hbu3Gmff/65hYWF2eTJk83MLD4+3sLCwqxXr162ceNG++abb6xatWomyX799VczM1u8eLFJsiNHjpiZWdeuXe3qq6+2devW2Y4dO2z27Nm2dOlSS05Ots8//9wk2datW23//v129OhRMzN79tlnrUaNGvbdd9/Zjh07bNKkSRYUFGRLlizx2kadOnVs3rx5tn37dvvnn38yzFuSffHFF1anTh2bOnWqmZn98ccfFhQUZL///rtJssWLF5uZWVJSktWsWdPuvPNOW7dunW3atMluvfVWq169uiUmJpqZ2cKFC23q1Km2efNm27Rpk/Xr18/Cw8MtISHBzMw+++wzCw4Otm+++cb++OMP++mnn7zazh1PWiEhITZp0iRPu0iySpUqedph3759F2wb9/vcn9umTZusadOm1qBBA2vTpo0tX77cfvnlF6tatardfffdWW7ztOudM2eObd261a6//nqrWLGinTlzxhITE23s2LEWHBxs+/fvt/3799uxY8cy7YcAgMuDohsA4HM//fSTSbKZM2eed7l58+ZZ3rx5bc+ePZ5pGzduNEn2888/m1nWi+4WLVp4LdOoUSMbPny453VGBVdGRXfFihUtOTnZM+2GG26wm266yczMNm/ebJJs1apVnvnbtm0zSRcsuvPkyWNFihSxggULmiSTZK+99ppnmSpVqti0adO83vfMM89YTEyMmZmNHz/eSpQoYadOnfLMnzhx4nmL7ujoaBs5cmSGMZ27rJnZ6dOnrXDhwvbjjz96LduvXz+75ZZbvN43a9asTPN1c3/mY8eOtbZt25qZ2ahRo+w///mPHTlyxKvonjp1qlWvXt1SU1M9709MTLRChQrZ3LlzM1x/SkqKFStWzGbPnm1mZq+++qpVq1bNkpKSzhtPWhkV3WPHjvVa5kJt437fe++955n/ySefmCRbuHChZ9qYMWOsevXql7Re9/jYvHmzmZlNmjTJQkJCMswXAOAfXNMNAPA5M8vScps3b1b58uVVvnx5z7SoqCiFhoZq8+bNatSoUZa3WadOHa/XZcqU0cGDB7P8frdatWopb968XutZv369JGnr1q3Kly+frrrqKs/8qlWrqnjx4hdcb/Xq1fXVV1/p9OnT+uijj7R27VoNGTJEknTixAnt2LFD/fr104ABAzzvSU5O9twUbevWrapTp44KFizomd+4cePzbnPo0KG65557NG/ePMXGxqpnz57pPqe0tm/frpMnT+rqq6/2mp6UlKT69et7TWvYsOEFc3br1auXHn30Ue3cuVOTJ0/Wm2++mW6Z3377Tdu3b1exYsW8pp8+fVo7duyQJB04cEBPPPGElixZooMHDyolJUUnT57Unj17JEk33HCDxo4dq8qVK6tTp07q0qWLrrnmmkyvN89M2tyy0jZuaT/b8PBwSVJ0dLTXNHefzO56y5QpI0k6ePCgatSocVF5AQAuD4puAIDPXXnllXK5XDlys7Q8efKkK+LTXmPtdu7Nrlwul1JTUy96ezm1nnMVKFBAVatWlSS98MIL6tq1q0aNGqVnnnlGx48flyRNnDhRTZo08Xpf2i8ALlb//v3VsWNHff3115o3b57GjBmjV1991VPsn8sdx9dff60rrrjCa15QUJDX6yJFimQ5jhIlSqhbt27q16+fTp8+rc6dO+vYsWPptt2gQQPPNdRplSpVStLZ68P/+ecfvfHGG6pYsaKCgoIUExOjpKQkSWdv2rZ161YtWLBA8+fP17333quXX35ZS5cuVf78+eVyubLUl9LmdjFtk7bvuFyuDKe5+9Klrjcn+iQAwDe4kRoAwOfCwsLUsWNHjRs3TidOnEg3332jr5o1a2rv3r3au3evZ96mTZt09OhRRUVFSTpbcO3fv9/r/e4bh12M/PnzKyUl5aLfl1b16tWVnJysX3/91TNt+/btOnLkyEWv64knntArr7yiffv2KTw8XGXLltXOnTtVtWpVr5/IyEjPttevX6/ExETPOlatWnXB7ZQvX1533323Zs6cqQcffFATJ06UdPZLAElen0lUVJSCgoK0Z8+edHGkPRshO+68804tWbJEvXv3zvCLhKuuukrbtm1T6dKl023bfeT3hx9+0NChQ9WlSxfVqlVLQUFB+vvvv73WU6hQIV1zzTV68803tWTJEq1YscJzpsK5fWnbtm06efLkeePOSttkR06tt0CBApfcrwEAOYuiGwBwWYwbN04pKSlq3LixPv/8c23btk2bN2/Wm2++qZiYGElSbGysoqOjddttt+mXX37Rzz//rN69e6t169aeU3zbtWun1atXa8qUKdq2bZuefvppbdiw4aLjqVSpkhYuXKi4uLhsFcmSVKNGDcXGxmrgwIH6+eef9euvv2rgwIEqVKiQ5whkVsXExKhOnTp6/vnnJUmjRo3SmDFj9Oabb+r333/X+vXrNWnSJL322muSpFtvvVWpqakaOHCgNm/erLlz5+qVV16RpEy3PWzYMM2dO1e7du3SL7/8osWLF6tmzZqSpIoVK8rlcmnOnDk6dOiQjh8/rmLFiumhhx7S/fffrw8//FA7duzQL7/8orfeeksffvhhtj4zt06dOunQoUMaPXp0hvNvu+02lSxZUt27d9f333+vXbt2acmSJRo6dKj+/PNPSWfPoJg6dao2b96sn376SbfddpsKFSrkWcfkyZP1/vvva8OGDdq5c6c++ugjFSpUSBUrVpR0ti+9/fbb+vXXX7V69WrdfffdWXoc2IXaJrtyYr2VKlXS8ePHtXDhQv39998X/BIBAOB7FN0AgMuicuXK+uWXX9S2bVs9+OCDql27tq6++motXLhQ48ePl3S2WPzyyy9VvHhxtWrVSrGxsapcubLXs6s7duyoJ598Uo888ogaNWqkY8eOqXfv3hcdz6uvvqr58+erfPny6a5PvhhTpkxReHi4WrVqpf/85z8aMGCAihUr5nWtdVbdf//9eu+997R37171799f7733niZNmqTo6Gi1bt1akydP9hz1DA4O1uzZs7V27VrVq1dPjz/+uJ566ilJynTbKSkpGjRokGrWrKlOnTqpWrVqnkdSXXHFFRo1apQeffRRhYeHa/DgwZKkZ555Rk8++aTGjBnjed/XX399SUd1pbNtXbJkSc8R9nMVLlxYy5YtU4UKFdSjRw/VrFnTczp6cHCwJOn999/XkSNHdNVVV+n222/X0KFDVbp0ac86QkNDNXHiRDVv3lx16tTRggULNHv2bJUoUULS2T5Qvnx5tWzZUrfeeqseeughFS5c+IKxX6htsisn1tusWTPdfffduummm1SqVCm99NJLlxQTAODSuSyrd7cBAAAX9Oeff6p8+fJasGCB2rdvf1m3/fHHH3ue05z2iC8AAPAfbqQGAMAlWLRokY4fP67o6Gjt379fjzzyiCpVqqRWrVr5fNtTpkxR5cqVdcUVV+i3337T8OHDdeONN1JwAwAQQCi6AQC4BGfOnNFjjz2mnTt3qlixYmrWrJk+/vjjLF0bfKni4uL01FNPKS4uTmXKlNENN9yg5557zufbBQAAWcfp5QAAAAAA+Ag3UgMAAAAAwEcougEAAAAA8BGKbgAAAAAAfISiGwAAAAAAH6HoBgAAAADARyi6AQAAAADwEYpuAAAAAAB8hKIbAAAAAAAfoegGAAAAAMBH/h8I5Yb+oPF7bwAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -382,7 +437,14 @@ "cell_type": "code", "execution_count": 7, "id": "e8901c56", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-26T21:20:43.252843Z", + "iopub.status.busy": "2026-02-26T21:20:43.250737Z", + "iopub.status.idle": "2026-02-26T21:20:50.290397Z", + "shell.execute_reply": "2026-02-26T21:20:50.286177Z" + } + }, "outputs": [ { "name": "stdout", @@ -392,13 +454,13 @@ "Search space size N = 8\n", "\n", "Counting register distribution (top outcomes):\n", - " |01011>: 687 counts -> phase = 0.1562, M ~ 1.7777\n", - " |10101>: 671 counts -> phase = 0.1562, M ~ 1.7777\n", - " |10110>: 204 counts -> phase = 0.1875, M ~ 2.4693\n", - " |01010>: 173 counts -> phase = 0.1875, M ~ 2.4693\n", - " |01100>: 51 counts -> phase = 0.1250, M ~ 1.1716\n", - " |10100>: 39 counts -> phase = 0.1250, M ~ 1.1716\n", - " ... (23 more outcomes)\n", + " |10101>: 452 counts -> phase = 0.1562, M ~ 1.7777\n", + " |01011>: 446 counts -> phase = 0.1562, M ~ 1.7777\n", + " |10000>: 177 counts -> phase = 0.0000, M ~ 0.0000\n", + " |10110>: 115 counts -> phase = 0.1875, M ~ 2.4693\n", + " |00000>: 111 counts -> phase = 0.5000, M ~ 8.0000\n", + " |01010>: 104 counts -> phase = 0.1875, M ~ 2.4693\n", + " ... (26 more outcomes)\n", "\n", "Best estimate of M: 1.777719067921591\n", "\n", @@ -422,7 +484,7 @@ ")\n", "\n", "device = LocalSimulator()\n", - "task_2 = device.run(circ_2, shots=2000)\n", + "task_2 = run_quantum_counting(circ_2, device, shots=2000)\n", "\n", "print(f\"Quantum Counting Results (N={N_2}, M={len(marked_states_2)}):\")\n", "results_2 = get_quantum_counting_results(\n", @@ -437,11 +499,18 @@ "cell_type": "code", "execution_count": 8, "id": "histogram2", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-26T21:20:50.293744Z", + "iopub.status.busy": "2026-02-26T21:20:50.293511Z", + "iopub.status.idle": "2026-02-26T21:20:51.563858Z", + "shell.execute_reply": "2026-02-26T21:20:51.562244Z" + } + }, "outputs": [ { "data": { - "image/png": "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X3311apQoYLmzp2bqvVPmDBB5cuX15NPPqlXXnlFZcuW1YMPPqhx48YlW3bbtm268cYb1bZtW73yyisqWrSo7rzzTm3YsMEpy4ABAyRJTz75pHMaco0aNVJVtv79+2vr1q0aMWKErr/+er311lsaOnSoOnfurISEBD3//PNq0aKFXn75ZU2fPv286/rhhx906NAh3XbbbcqdO/cFY+/fv19XXnml5s+frwcffFDPPfecTp06peuvv16ffvppquojSYcPH9a1116runXr6pVXXlH16tU1ePBgffXVV5KkGjVqaOTIkZKke++912nDq6+++rzrnTlzpl5++WXdd999GjVqlHbu3KkbbrhBp0+fdpb54osvdMsttyhv3rwaPXq0brjhBvXu3VurV69OdX2k/yXGSZPA5557Tj179tQVV1yhV199VQMHDtTixYt19dVX68iRI5LOJHPt27fXihUr1L9/f40bN0733nuvtm/f7iyTFmPHjlWZMmVUvXp1px2feuopSWd+gBoxYoRat26tN998U0899ZTKlSunNWvWnHedq1evVlxcnBo0aHDOZZ566inFx8frhRdeOO+6Tp8+rb///vui/pJeM9+qVSvFxMTovvvu06ZNm7Rr1y5NnDhRs2fP1pAhQy6hhZKrUKGCIiMj9f777zvTvvrqKx09elTdu3dP8T2HDx++qDqcPHnygvGjo6NVoEABFShQIGB6aGioKleurB9//DFN9QMAT3l9qB0AkNyRI0dMknXp0uW8y11//fUmyWJiYszMrFevXla+fPlkyz3zzDN29i7/5MmTyZZr3769VapUKWBa+fLlTZJ99913zrQDBw5YUFCQPfLII860851eLsmeeeaZZNPLly9vvXr1cl77T3Vt3759wGngkZGR5vP57P7773emxcfHW5kyZS54CvF//vMfk2SffvrpeZfzGzhwoEmy77//3pl27Ngxq1ixolWoUMESEhICypr0lGaz/51OnLQdWrZsaZJs2rRpzrTY2FgLDw+3bt26OdPOd3r52dt2x44dJsmKFy9uhw4dcqZ/9tlnJsnmzp3rTKtdu7aVKVPGjh075kxbsmSJSUqxv5ytZcuWVr16dTt48KAdPHjQNm/ebI899phJCjjleOfOnZY7d2577rnnAt6/bt06y5MnjzP9l19+ueAp1/76pdQWZ/enSzm9vG7duqk6TXry5MkmydatW5dsXtJTr++66y4LDg62vXv3mlnKp5f7p13MX9I6xcfHW79+/Sxv3rzO/Ny5c9uECRMuuT5+/rZbtWqVvfnmm1a4cGFn33DTTTdZ69atk9Uxab0vpg4pjf2ktm7dasHBwXbHHXekOL9du3ZWo0aNVNcRALyWx5VMHgCQJv5TLAsXLnze5fzzjx07dsFlz5b0dNSjR4/q9OnTatmypebPn6+jR48qNDTUmR8RERFwxP2yyy5TtWrVtH379kuKebF69+4dcBp406ZNtXz5cvXu3duZljt3bjVq1OiCR2tjYmIkXbgt/b788ks1adJELVq0cKYVKlRI9957r4YMGaKNGzeqVq1al1IdZx09evRwXufLl09NmjRJcxvecsstKlq0qPPav5386927d6/WrVunJ598MuCO2y1btlTt2rWd9rmQzZs3J7vM4frrr9fbb7/tvJ49e7YSExN188036++//3amh4eH64orrtC3336rJ5980ulb8+fP13XXXZfs6KabihQpog0bNmjr1q264oorLvp9//zzjyQFtHVKnn76aU2fPl0vvPCC/vOf/6S4TN26dS94OrtfeHi48//cuXOrcuXKat++vW666SYFBwfr/fffV//+/RUeHq6uXbteXGXO4eabb9bAgQM1b948XXvttZo3b55ef/31cy7/3nvv6d9//73geitVqnTOeSdPntRNN92k/Pnzn/MMgaJFi+qXX365cAUAIJMi6QaATChpMn0+x44dk8/nS3aN5MX48ccf9cwzz2j58uXJTv88O+kuV65csvcXLVpUhw8fvuS4F+PseP6ylC1bNtn0C5UhJCRE0oXb0m/Xrl0pPhvYf6r8rl27UpV0lylTJtn15EWLFtVvv/12yetK6uy28ieF/nbZtWuXJKlKlSrJ3lulSpULnlbtV6FCBU2aNEmJiYn6448/9Nxzz+ngwYMKDg52ltm6davM7JzJbN68eSVJFStW1KBBg/Tqq6/qvffe01VXXaXrr79ePXr0COh3bhg5cqS6dOmiqlWrqlatWrr22mt1xx13qE6dOhf1frvAPQQqVaqkO+64Q2+99ZaeeOKJFJcpWrToOa8NPx9/Ir9161bnB5Sbb75ZrVu3Vt++fdWpUyflyZP6r3aXXXaZoqKiNHPmTJ08eVIJCQm68cYbz7l88+bNUx1LOvMItu7du2vjxo366quvVLp06RSXM7MU78UAAFkFSTcAZEKhoaEqXbr0BROy3377TWXKlFG+fPkk6ZxfTM9+hu8ff/yha665RtWrV9err76qsmXLKl++fPryyy/12muvJXv28rmuhb5QAnIh53q28LnipTT9QmWoXr26JGndunVpPhKY1MW2tZ9bbejWes9WsGDBgESxefPmatCggZ588knnaGhiYqJ8Pp+++uqrFMuV9Ej7K6+8ojvvvFOfffaZFixYoAEDBmj06NFasWJFij9Q+KX2edR+V199tf744w8n7uTJk/Xaa69p4sSJ6tOnzznfV7x4cUlnfswoU6bMeWM89dRTmj59ul588cUU+1xcXJwOHTp0UeW97LLLnLYcP3682rRpE9CO0pkzDgYNGqSdO3em+OPKpbjtttt0zz33KDo6Wh06dEh207akDh48eFHbo1ChQsnKLEn33HOP5s2bp/fee09t2rQ55/sPHz6cqh8WASCz4EZqAJBJde7cWTt27NAPP/yQ4vzvv/9eO3fudO4aLp05gpbSjaj8Rzv95s6dq9jYWH3++ee67777dN111ykqKipNd0A+35GolMoVFxenffv2pTrexWrRooWKFi2q999//6IShPLly6f4POzNmzc786X/HVE+u15nt/WlcONonr+827ZtSzYvpWkXq06dOurRo4f++9//avfu3ZKkypUry8xUsWJFRUVFJftr1qxZwDpq166tp59+Wt99952+//57/fXXX5o4caKktLfv+dqyWLFiuuuuu/T+++9rz549qlOnznnvhi7978ebHTt2XDB25cqVnbZJqY8vW7ZMpUqVuqi/pHd9379/f4p92H/TvPj4+AuW7UL+7//+T7ly5dKKFSsueNfyxo0bX1QdUnrO9mOPPaYpU6botdde06233nreODt27Ej1TRkBIDMg6QaATOrRRx9VgQIFdN999znXk/odOnRI999/v0JCQtSvXz9neuXKlXX06NGAI+T79u1Ldtdt/5GzpEdDjx49qilTpqS6vAULFpSUPEnyl+u7774LmPbWW2+l+ajlxShQoIAGDx6sTZs2afDgwSkeAZ4xY4Z++uknSdJ1112nn376ScuXL3fmnzhxQm+99ZYqVKigiIgISWfqJCmgXgkJCXrrrbdSXdbztWFqlS5dWrVq1dK0adN0/PhxZ/rSpUu1bt26NK378ccf1+nTp/Xqq69Kkm644Qblzp1bI0aMSNbOZub045iYmGQJYu3atZUrVy7FxsZKOnNZQIkSJZL1m/Hjx19U2QoWLJhiO549lgoVKqQqVao4cc+lYcOGypcvn37++eeLiv/000/r9OnTAY+F8/Nf030xf0mv6a5ataoWLlwYUIeEhAR9+OGHKly4sNMn06JQoUKaMGGChg8frs6dO5932ffee++i6tCzZ8+A97388ssaM2aMnnzyST300EPnjXH06FH98ccfuvLKK9NcNwDwCqeXA0AmVaVKFU2bNk233nqrateurd69e6tixYrauXOn3n77bR0+fFizZs1SxYoVnfd0795dgwcP1v/93/9pwIABOnnypCZMmKCqVasGXLvbrl075cuXT507d9Z9992n48ePa9KkSSpZsmSqjz7Xq1dPuXPn1osvvqijR48qKCjIeQ54nz59dP/996tbt25q27atfv31V82fPz/DThl97LHHtGHDBr3yyiv69ttvdeONNyo8PFzR0dGaM2eOfvrpJy1btkyS9MQTT+j9999Xhw4dNGDAABUrVkzvvvuuduzYoU8++US5cp35vbpmzZpq1qyZhgwZokOHDqlYsWKaNWtWmo42Vq5cWUWKFNHEiRNVuHBhFSxYUE2bNg3Yxqnx/PPPq0uXLmrevLnuuusuHT58WG+++aZq1aoVkIhfqoiICF133XWaPHmyhg4dqsqVK2vUqFEaMmSIdu7cqa5du6pw4cLasWOHPv30U91777169NFH9c0336hfv3666aabVLVqVcXHx2v69OnKnTu3unXr5qy/T58+euGFF9SnTx81atRI3333nX7//feLKlvDhg01YcIEjRo1SlWqVFHJkiXVpk0bRUREqFWrVmrYsKGKFSumn3/+WR9//HHAj1cpCQ4OVrt27bRo0SLn0W7n4z/a/e677yabl9prup944gn16NFDTZs21b333qv8+fPr/fff1+rVqzVq1CjnmnnpzHPd/f32Up/F3qtXr4taLjXXdH/66ad6/PHHdcUVV6hGjRqaMWNGwPy2bdsqLCzMeb1o0SKZmbp06XLJsQAg0/DknukAgIu2bt06u+222yw8PNxy5cplkiw4ONg2bNiQ4vILFiywWrVqWb58+axatWo2Y8aMFB8Z9vnnn1udOnUsODjYKlSoYC+++KK98847yR5TlNKjgszOPEbq7EcyTZo0ySpVqmS5c+cOeGxWQkKCDR482EqUKGEFChSw9u3b27Zt2875yLBVq1YFrNdf/oMHDwZM79WrlxUsWPACLfg/H3/8sbVr186KFStmefLksVKlStktt9xiS5YsCVjujz/+sBtvvNGKFCliwcHB1qRJE5s3b16y9f3xxx8WFRVlQUFBFhYWZk8++aQtXLgwxUeG1axZM9n7U3rE22effWYRERGWJ0+egEdmneuRYS+//HKy9SqFxzTNmjXLqlevbkFBQVarVi37/PPPrVu3bla9evXzN9p5ym/2v0ePJY33ySefWIsWLaxgwYJWsGBBq169uvXt29e2bNliZmbbt2+3u+++2ypXrmzBwcFWrFgxa926tS1atChg3SdPnrTevXtbaGioFS5c2G6++WY7cODART0yLDo62jp27GiFCxc2SU5fHTVqlDVp0sSKFCli+fPnt+rVq9tzzz1ncXFxF2yH2bNnm8/ns927dwdMP9cY2bp1qzMWzvd4tEvx9ddfW8uWLa1EiRKWL18+q127tk2cODHZct26dbP8+fPb4cOHz7u+c425s52rjpfKP5bP9Xf2IwdvueUWa9GiRZrjAoCXfGbpfKcVAICrpk2bpjvvvFM9evTQtGnTvC4OsrB69erpsssuu+jHV+V0CQkJioiI0M0336xnn33W6+KcV1hYmHr27KmXX37Z66KkWnR0tCpWrKhZs2ZxpBtAlsY13QCQxfTs2VOjR4/W9OnT9eSTT3pdHGQBp0+fTnba+5IlS/Trr7+qVatW3hQqC8qdO7dGjhypcePGpem0fLdt2LBB//77rwYPHux1UdJk7Nixql27Ngk3gCyPI90AAGRzO3fuVFRUlHr06KHSpUtr8+bNmjhxokJDQ7V+/XrncVgAACD9cSM1AACyuaJFi6phw4aaPHmyDh48qIIFC6pjx4564YUXSLgBAHAZR7oBAAAAAHAJ13QDAAAAAOASkm4AAAAAAFzCNd2SEhMTtXfvXhUuXFg+n8/r4gAAAAAAMjkz07Fjx1S6dGnlynXu49kk3ZL27t2rsmXLel0MAAAAAEAWs2fPHpUpU+ac80m6JRUuXFjSmcYKCQnxuDQAAAAAgMwuJiZGZcuWdfLJcyHplpxTykNCQki6AQAAAAAX7UKXKHMjNQAAAAAAXELSDQAAAACAS0i6AQAAAABwCUk3AAAAAAAu8TTprlChgnw+X7K/vn37SpJOnTqlvn37qnjx4ipUqJC6deum/fv3B6xj9+7d6tixowoUKKCSJUvqscceU3x8vBfVAQAAAAAggKdJ96pVq7Rv3z7nb+HChZKkm266SZL08MMPa+7cufroo4+0dOlS7d27VzfccIPz/oSEBHXs2FFxcXFatmyZ3n33XU2dOlXDhg3zpD4AAAAAACTlMzPzuhB+AwcO1Lx587R161bFxMTosssu08yZM3XjjTdKkjZv3qwaNWpo+fLlatasmb766it16tRJe/fuVVhYmCRp4sSJGjx4sA4ePKh8+fJdVNyYmBiFhobq6NGjPDIMAAAAAHBBF5tHZppruuPi4jRjxgzdfffd8vl8Wr16tU6fPq2oqChnmerVq6tcuXJavny5JGn58uWqXbu2k3BLUvv27RUTE6MNGzacM1ZsbKxiYmIC/gAAAAAASG+ZJumeM2eOjhw5ojvvvFOSFB0drXz58qlIkSIBy4WFhSk6OtpZJmnC7Z/vn3cuo0ePVmhoqPNXtmzZ9KsIAAAAAAD/X6ZJut9++2116NBBpUuXdj3WkCFDdPToUedvz549rscEAAAAAOQ8ebwugCTt2rVLixYt0uzZs51p4eHhiouL05EjRwKOdu/fv1/h4eHOMj/99FPAuvx3N/cvk5KgoCAFBQWlYw0AAAAAAEguUxzpnjJlikqWLKmOHTs60xo2bKi8efNq8eLFzrQtW7Zo9+7dioyMlCRFRkZq3bp1OnDggLPMwoULFRISooiIiIyrAAAAAAAAKfD8SHdiYqKmTJmiXr16KU+e/xUnNDRUvXv31qBBg1SsWDGFhISof//+ioyMVLNmzSRJ7dq1U0REhO644w699NJLio6O1tNPP62+fftyJBsAAAAA4DnPk+5FixZp9+7duvvuu5PNe+2115QrVy5169ZNsbGxat++vcaPH+/Mz507t+bNm6cHHnhAkZGRKliwoHr16qWRI0dmZBUAAAAAAEhRpnpOt1d4TjcAAAAA4FJcbB7p+ZFuXLx+k39wbd1v9mnh2roBAAAAIKfKFDdSAwAAAAAgOyLpBgAAAADAJSTdAAAAAAC4hKQbAAAAAACXkHQDAAAAAOASkm4AAAAAAFxC0g0AAAAAgEt4TjfOi2eDAwAAAEDqcaQbAAAAAACXkHQDAAAAAOASkm4AAAAAAFxC0g0AAAAAgEtIugEAAAAAcAlJNwAAAAAALiHpBgAAAADAJSTdAAAAAAC4hKQbAAAAAACXkHQDAAAAAOASkm4AAAAAAFxC0g0AAAAAgEtIugEAAAAAcAlJNwAAAAAALiHpBgAAAADAJSTdAAAAAAC4hKQbAAAAAACXkHQDAAAAAOASkm4AAAAAAFxC0g0AAAAAgEtIugEAAAAAcAlJNwAAAAAALiHpBgAAAADAJSTdAAAAAAC4hKQbAAAAAACXkHQDAAAAAOASkm4AAAAAAFxC0g0AAAAAgEtIugEAAAAAcAlJNwAAAAAALvE86f7rr7/Uo0cPFS9eXPnz51ft2rX1888/O/PNTMOGDVOpUqWUP39+RUVFaevWrQHrOHTokG6//XaFhISoSJEi6t27t44fP57RVQEAAAAAIICnSffhw4fVvHlz5c2bV1999ZU2btyoV155RUWLFnWWeemll/T6669r4sSJWrlypQoWLKj27dvr1KlTzjK33367NmzYoIULF2revHn67rvvdO+993pRJQAAAAAAHHm8DP7iiy+qbNmymjJlijOtYsWKzv/NTGPHjtXTTz+tLl26SJKmTZumsLAwzZkzR927d9emTZv09ddfa9WqVWrUqJEk6Y033tB1112nMWPGqHTp0hlbKQAAAAAA/j9Pj3R//vnnatSokW666SaVLFlS9evX16RJk5z5O3bsUHR0tKKiopxpoaGhatq0qZYvXy5JWr58uYoUKeIk3JIUFRWlXLlyaeXKlRlXGQAAAAAAzuJp0r19+3ZNmDBBV1xxhebPn68HHnhAAwYM0LvvvitJio6OliSFhYUFvC8sLMyZFx0drZIlSwbMz5Mnj4oVK+Ysc7bY2FjFxMQE/AEAAAAAkN48Pb08MTFRjRo10vPPPy9Jql+/vtavX6+JEyeqV69ersUdPXq0RowY4dr6AQAAAACQPD7SXapUKUVERARMq1Gjhnbv3i1JCg8PlyTt378/YJn9+/c788LDw3XgwIGA+fHx8Tp06JCzzNmGDBmio0ePOn979uxJl/oAAAAAAJCUp0l38+bNtWXLloBpv//+u8qXLy/pzE3VwsPDtXjxYmd+TEyMVq5cqcjISElSZGSkjhw5otWrVzvLfPPNN0pMTFTTpk1TjBsUFKSQkJCAPwAAAAAA0punp5c//PDDuvLKK/X888/r5ptv1k8//aS33npLb731liTJ5/Np4MCBGjVqlK644gpVrFhRQ4cOVenSpdW1a1dJZ46MX3vttbrnnns0ceJEnT59Wv369VP37t25czkAAAAAwFOeJt2NGzfWp59+qiFDhmjkyJGqWLGixo4dq9tvv91Z5vHHH9eJEyd077336siRI2rRooW+/vprBQcHO8u899576tevn6655hrlypVL3bp10+uvv+5FlQAAAAAAcPjMzLwuhNdiYmIUGhqqo0ePZupTzftN/sG1db/Zp0WmiQkAAAAAmd3F5pGeXtMNAAAAAEB2RtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgEk+T7uHDh8vn8wX8Va9e3Zl/6tQp9e3bV8WLF1ehQoXUrVs37d+/P2Adu3fvVseOHVWgQAGVLFlSjz32mOLj4zO6KgAAAAAAJJPH6wLUrFlTixYtcl7nyfO/Ij388MP64osv9NFHHyk0NFT9+vXTDTfcoB9//FGSlJCQoI4dOyo8PFzLli3Tvn371LNnT+XNm1fPP/98htcFAAAAAICkPE+68+TJo/Dw8GTTjx49qrffflszZ85UmzZtJElTpkxRjRo1tGLFCjVr1kwLFizQxo0btWjRIoWFhalevXp69tlnNXjwYA0fPlz58uXL6OoAAAAAAODw/JrurVu3qnTp0qpUqZJuv/127d69W5K0evVqnT59WlFRUc6y1atXV7ly5bR8+XJJ0vLly1W7dm2FhYU5y7Rv314xMTHasGHDOWPGxsYqJiYm4A8AAAAAgPTmadLdtGlTTZ06VV9//bUmTJigHTt26KqrrtKxY8cUHR2tfPnyqUiRIgHvCQsLU3R0tCQpOjo6IOH2z/fPO5fRo0crNDTU+Stbtmz6VgwAAAAAAHl8enmHDh2c/9epU0dNmzZV+fLl9eGHHyp//vyuxR0yZIgGDRrkvI6JiSHxBgAAAACkO89PL0+qSJEiqlq1qrZt26bw8HDFxcXpyJEjAcvs37/fuQY8PDw82d3M/a9Tuk7cLygoSCEhIQF/AAAAAACkt0yVdB8/flx//PGHSpUqpYYNGypv3rxavHixM3/Lli3avXu3IiMjJUmRkZFat26dDhw44CyzcOFChYSEKCIiIsPLDwAAAABAUp6eXv7oo4+qc+fOKl++vPbu3atnnnlGuXPn1q233qrQ0FD17t1bgwYNUrFixRQSEqL+/fsrMjJSzZo1kyS1a9dOERERuuOOO/TSSy8pOjpaTz/9tPr27augoCAvqwYAAAAAgLdJ959//qlbb71V//zzjy677DK1aNFCK1as0GWXXSZJeu2115QrVy5169ZNsbGxat++vcaPH++8P3fu3Jo3b54eeOABRUZGqmDBgurVq5dGjhzpVZUAAAAAAHB4mnTPmjXrvPODg4M1btw4jRs37pzLlC9fXl9++WV6Fw0AAAAAgDTLVNd0AwAAAACQnZB0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuCTTJN0vvPCCfD6fBg4c6Ew7deqU+vbtq+LFi6tQoULq1q2b9u/fH/C+3bt3q2PHjipQoIBKliypxx57TPHx8RlcegAAAAAAkssUSfeqVav03//+V3Xq1AmY/vDDD2vu3Ln66KOPtHTpUu3du1c33HCDMz8hIUEdO3ZUXFycli1bpnfffVdTp07VsGHDMroKAAAAAAAkk6qke82aNVq3bp3z+rPPPlPXrl315JNPKi4u7pLWdfz4cd1+++2aNGmSihYt6kw/evSo3n77bb366qtq06aNGjZsqClTpmjZsmVasWKFJGnBggXauHGjZsyYoXr16qlDhw569tlnNW7cuEsuBwAAAAAA6S1VSfd9992n33//XZK0fft2de/eXQUKFNBHH32kxx9//JLW1bdvX3Xs2FFRUVEB01evXq3Tp08HTK9evbrKlSun5cuXS5KWL1+u2rVrKywszFmmffv2iomJ0YYNG84ZMzY2VjExMQF/AAAAAACkt1Ql3b///rvq1asnSfroo4909dVXa+bMmZo6dao++eSTi17PrFmztGbNGo0ePTrZvOjoaOXLl09FihQJmB4WFqbo6GhnmaQJt3++f965jB49WqGhoc5f2bJlL7rMAAAAAABcrFQl3WamxMRESdKiRYt03XXXSZLKli2rv//++6LWsWfPHj300EN67733FBwcnJpipNqQIUN09OhR52/Pnj0ZGh8AAAAAkDOkKulu1KiRRo0apenTp2vp0qXq2LGjJGnHjh3Jjjyfy+rVq3XgwAE1aNBAefLkUZ48ebR06VK9/vrrypMnj8LCwhQXF6cjR44EvG///v0KDw+XJIWHhye7m7n/tX+ZlAQFBSkkJCTgDwAAAACA9JaqpPu1117TmjVr1K9fPz311FOqUqWKJOnjjz/WlVdeeVHruOaaa7Ru3TqtXbvW+WvUqJFuv/125/958+bV4sWLnfds2bJFu3fvVmRkpCQpMjJS69at04EDB5xlFi5cqJCQEEVERKSmagAAAAAApJs8qXlT3bp1A+5e7vfyyy8rT56LW2XhwoVVq1atgGkFCxZU8eLFnem9e/fWoEGDVKxYMYWEhKh///6KjIxUs2bNJEnt2rVTRESE7rjjDr300kuKjo7W008/rb59+yooKCg1VQMAAAAAIN2k6kh3pUqV9M8//ySbfurUKVWtWjXNhfJ77bXX1KlTJ3Xr1k1XX321wsPDNXv2bGd+7ty5NW/ePOXOnVuRkZHq0aOHevbsqZEjR6ZbGQAAAAAASK1UHeneuXOnEhISkk2PjY3Vn3/+merCLFmyJOB1cHCwxo0bp3Hjxp3zPeXLl9eXX36Z6pgAAAAAALjlkpLuzz//3Pn//PnzFRoa6rxOSEjQ4sWLVbFixfQrHQAAAAAAWdglJd1du3aVJPl8PvXq1StgXt68eVWhQgW98sor6VY4AAAAAACysktKuv3P5q5YsaJWrVqlEiVKuFIoAAAAAACyg1Rd071jx470LgcAAAAAANlOqpJuSVq8eLEWL16sAwcOOEfA/d555500FwwAAAAAgKwuVUn3iBEjNHLkSDVq1EilSpWSz+dL73IBAAAAAJDlpSrpnjhxoqZOnao77rgjvcsDAAAAAEC2kSs1b4qLi9OVV16Z3mUBAAAAACBbSVXS3adPH82cOTO9ywIAAAAAQLaSqtPLT506pbfeekuLFi1SnTp1lDdv3oD5r776aroUDgAAAACArCxVSfdvv/2mevXqSZLWr18fMI+bqgEAAAAAcEaqku5vv/02vcsBAAAAAEC2k6prugEAAAAAwIWl6kh369atz3sa+TfffJPqAgEAAAAAkF2kKun2X8/td/r0aa1du1br169Xr1690qNcAAAAAABkealKul977bUUpw8fPlzHjx9PU4EAAAAAAMgu0vWa7h49euidd95Jz1UCAAAAAJBlpWvSvXz5cgUHB6fnKgEAAAAAyLJSdXr5DTfcEPDazLRv3z79/PPPGjp0aLoUDAAAAACArC5VSXdoaGjA61y5cqlatWoaOXKk2rVrly4FAwAAAAAgq0tV0j1lypT0LgcAAAAAANlOqpJuv9WrV2vTpk2SpJo1a6p+/frpUigAAAAAALKDVCXdBw4cUPfu3bVkyRIVKVJEknTkyBG1bt1as2bN0mWXXZaeZQQAAAAAIEtK1d3L+/fvr2PHjmnDhg06dOiQDh06pPXr1ysmJkYDBgxI7zICAAAAAJAlpepI99dff61FixapRo0azrSIiAiNGzeOG6kBAAAAAPD/pepId2JiovLmzZtset68eZWYmJjmQgEAAAAAkB2kKulu06aNHnroIe3du9eZ9tdff+nhhx/WNddck26FAwAAAAAgK0tV0v3mm28qJiZGFSpUUOXKlVW5cmVVrFhRMTExeuONN9K7jAAAAAAAZEmpuqa7bNmyWrNmjRYtWqTNmzdLkmrUqKGoqKh0LRwAAAAAAFnZJR3p/uabbxQREaGYmBj5fD61bdtW/fv3V//+/dW4cWPVrFlT33//vVtlBQAAAAAgS7mkpHvs2LG65557FBISkmxeaGio7rvvPr366qvpVjgAAAAAALKyS0q6f/31V1177bXnnN+uXTutXr06zYUCAAAAACA7uKSke//+/Sk+KswvT548OnjwYJoLBQAAAABAdnBJSffll1+u9evXn3P+b7/9plKlSqW5UAAAAAAAZAeXlHRfd911Gjp0qE6dOpVs3r///qtnnnlGnTp1SrfCAQAAAACQlV3SI8OefvppzZ49W1WrVlW/fv1UrVo1SdLmzZs1btw4JSQk6KmnnnKloAAAAAAAZDWXlHSHhYVp2bJleuCBBzRkyBCZmSTJ5/Opffv2GjdunMLCwlwpKAAAAAAAWc0lJd2SVL58eX355Zc6fPiwtm3bJjPTFVdcoaJFi7pRPgAAAAAAsqxLTrr9ihYtqsaNG6dnWQAAAAAAyFYu6UZq6W3ChAmqU6eOQkJCFBISosjISH311VfO/FOnTqlv374qXry4ChUqpG7dumn//v0B69i9e7c6duyoAgUKqGTJknrssccUHx+f0VUBAAAAACAZT5PuMmXK6IUXXtDq1av1888/q02bNurSpYs2bNggSXr44Yc1d+5cffTRR1q6dKn27t2rG264wXl/QkKCOnbsqLi4OC1btkzvvvuupk6dqmHDhnlVJQAAAAAAHKk+vTw9dO7cOeD1c889pwkTJmjFihUqU6aM3n77bc2cOVNt2rSRJE2ZMkU1atTQihUr1KxZMy1YsEAbN27UokWLFBYWpnr16unZZ5/V4MGDNXz4cOXLl8+LagEAAAAAIMnjI91JJSQkaNasWTpx4oQiIyO1evVqnT59WlFRUc4y1atXV7ly5bR8+XJJ0vLly1W7du2AO6a3b99eMTExztFyAAAAAAC84umRbklat26dIiMjderUKRUqVEiffvqpIiIitHbtWuXLl09FihQJWD4sLEzR0dGSpOjo6GSPKPO/9i+TktjYWMXGxjqvY2Ji0qk2AAAAAAD8j+dHuqtVq6a1a9dq5cqVeuCBB9SrVy9t3LjR1ZijR49WaGio81e2bFlX4wEAAAAAcibPk+58+fKpSpUqatiwoUaPHq26devqP//5j8LDwxUXF6cjR44ELL9//36Fh4dLksLDw5Pdzdz/2r9MSoYMGaKjR486f3v27EnfSgEAAAAAoEyQdJ8tMTFRsbGxatiwofLmzavFixc787Zs2aLdu3crMjJSkhQZGal169bpwIEDzjILFy5USEiIIiIizhkjKCjIeUyZ/w8AAAAAgPTm6TXdQ4YMUYcOHVSuXDkdO3ZMM2fO1JIlSzR//nyFhoaqd+/eGjRokIoVK6aQkBD1799fkZGRatasmSSpXbt2ioiI0B133KGXXnpJ0dHRevrpp9W3b18FBQV5WTUAAAAAALxNug8cOKCePXtq3759Cg0NVZ06dTR//ny1bdtWkvTaa68pV65c6tatm2JjY9W+fXuNHz/eeX/u3Lk1b948PfDAA4qMjFTBggXVq1cvjRw50qsqAQAAAADg8DTpfvvtt887Pzg4WOPGjdO4cePOuUz58uX15ZdfpnfRAAAAAABIs0x3TTcAAAAAANkFSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLPE26R48ercaNG6tw4cIqWbKkunbtqi1btgQsc+rUKfXt21fFixdXoUKF1K1bN+3fvz9gmd27d6tjx44qUKCASpYsqccee0zx8fEZWRUAAAAAAJLxNOleunSp+vbtqxUrVmjhwoU6ffq02rVrpxMnTjjLPPzww5o7d64++ugjLV26VHv37tUNN9zgzE9ISFDHjh0VFxenZcuW6d1339XUqVM1bNgwL6oEAAAAAIAjj5fBv/7664DXU6dOVcmSJbV69WpdffXVOnr0qN5++23NnDlTbdq0kSRNmTJFNWrU0IoVK9SsWTMtWLBAGzdu1KJFixQWFqZ69erp2Wef1eDBgzV8+HDly5fPi6ohDfpN/sG1db/Zp4Vr6wYAAACAs2Wqa7qPHj0qSSpWrJgkafXq1Tp9+rSioqKcZapXr65y5cpp+fLlkqTly5erdu3aCgsLc5Zp3769YmJitGHDhhTjxMbGKiYmJuAPAAAAAID0lmmS7sTERA0cOFDNmzdXrVq1JEnR0dHKly+fihQpErBsWFiYoqOjnWWSJtz++f55KRk9erRCQ0Odv7Jly6ZzbQAAAAAAyERJd9++fbV+/XrNmjXL9VhDhgzR0aNHnb89e/a4HhMAAAAAkPN4ek23X79+/TRv3jx99913KlOmjDM9PDxccXFxOnLkSMDR7v379ys8PNxZ5qeffgpYn//u5v5lzhYUFKSgoKB0rgUAAAAAAIE8PdJtZurXr58+/fRTffPNN6pYsWLA/IYNGypv3rxavHixM23Lli3avXu3IiMjJUmRkZFat26dDhw44CyzcOFChYSEKCIiImMqAgAAAABACjw90t23b1/NnDlTn332mQoXLuxcgx0aGqr8+fMrNDRUvXv31qBBg1SsWDGFhISof//+ioyMVLNmzSRJ7dq1U0REhO644w699NJLio6O1tNPP62+fftyNBsAAAAA4ClPk+4JEyZIklq1ahUwfcqUKbrzzjslSa+99ppy5cqlbt26KTY2Vu3bt9f48eOdZXPnzq158+bpgQceUGRkpAoWLKhevXpp5MiRGVUNAAAAAABS5GnSbWYXXCY4OFjjxo3TuHHjzrlM+fLl9eWXX6Zn0QAAAAAASLNMc/dyAAAAAACyG5JuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuMTT53QDmUW/yT+4tu43+7Rwbd0AAAAAMjeOdAMAAAAA4BKSbgAAAAAAXELSDQAAAACAS0i6AQAAAABwCUk3AAAAAAAuIekGAAAAAMAlJN0AAAAAALiEpBsAAAAAAJeQdAMAAAAA4BKSbgAAAAAAXELSDQAAAACAS0i6AQAAAABwCUk3AAAAAAAuIekGAAAAAMAlJN0AAAAAALiEpBsAAAAAAJeQdAMAAAAA4BKSbgAAAAAAXELSDQAAAACAS0i6AQAAAABwCUk3AAAAAAAuIekGAAAAAMAlJN0AAAAAALiEpBsAAAAAAJeQdAMAAAAA4BKSbgAAAAAAXELSDQAAAACAS0i6AQAAAABwCUk3AAAAAAAuIekGAAAAAMAlJN0AAAAAALjE06T7u+++U+fOnVW6dGn5fD7NmTMnYL6ZadiwYSpVqpTy58+vqKgobd26NWCZQ4cO6fbbb1dISIiKFCmi3r176/jx4xlYCwAAAAAAUuZp0n3ixAnVrVtX48aNS3H+Sy+9pNdff10TJ07UypUrVbBgQbVv316nTp1ylrn99tu1YcMGLVy4UPPmzdN3332ne++9N6OqAAAAAADAOeXxMniHDh3UoUOHFOeZmcaOHaunn35aXbp0kSRNmzZNYWFhmjNnjrp3765Nmzbp66+/1qpVq9SoUSNJ0htvvKHrrrtOY8aMUenSpTOsLgAAAAAAnC3TXtO9Y8cORUdHKyoqypkWGhqqpk2bavny5ZKk5cuXq0iRIk7CLUlRUVHKlSuXVq5cmeFlBgAAAAAgKU+PdJ9PdHS0JCksLCxgelhYmDMvOjpaJUuWDJifJ08eFStWzFkmJbGxsYqNjXVex8TEpFexAQAAAABwZNoj3W4aPXq0QkNDnb+yZct6XSQAAAAAQDaUaZPu8PBwSdL+/fsDpu/fv9+ZFx4ergMHDgTMj4+P16FDh5xlUjJkyBAdPXrU+duzZ086lx4AAAAAgEycdFesWFHh4eFavHixMy0mJkYrV65UZGSkJCkyMlJHjhzR6tWrnWW++eYbJSYmqmnTpudcd1BQkEJCQgL+AAAAAABIb55e0338+HFt27bNeb1jxw6tXbtWxYoVU7ly5TRw4ECNGjVKV1xxhSpWrKihQ4eqdOnS6tq1qySpRo0auvbaa3XPPfdo4sSJOn36tPr166fu3btz53IAAAAAgOc8Tbp//vlntW7d2nk9aNAgSVKvXr00depUPf744zpx4oTuvfdeHTlyRC1atNDXX3+t4OBg5z3vvfee+vXrp2uuuUa5cuVSt27d9Prrr2d4XQAAAAAAOJunSXerVq1kZuec7/P5NHLkSI0cOfKcyxQrVkwzZ850o3gAAAAAAKRJpr2mGwAAAACArI6kGwAAAAAAl5B0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgEpJuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJSTcAAAAAAC4h6QYAAAAAwCUk3QAAAAAAuISkGwAAAAAAl5B0AwAAAADgkjxeFwDIqfpN/sG1db/Zp4Vr6wYAAABw8TjSDQAAAACAS0i6AQAAAABwCUk3AAAAAAAuIekGAAAAAMAlJN0AAAAAALiEu5cDOQh3TAcAAAAyFke6AQAAAABwCUk3AAAAAAAuIekGAAAAAMAlJN0AAAAAALiEG6kBcA03bgMAAEBOx5FuAAAAAABcQtINAAAAAIBLSLoBAAAAAHAJ13QDyFa4jhwAAACZCUe6AQAAAABwCUk3AAAAAAAu4fRyAEgjL05p5zR6AACArIEj3QAAAAAAuIQj3QCAi8IRfQAAgEuXbZLucePG6eWXX1Z0dLTq1q2rN954Q02aNPG6WACALCajE303450rJgAAyDjZIun+4IMPNGjQIE2cOFFNmzbV2LFj1b59e23ZskUlS5b0ungAAGQqnEEAAEDGyRZJ96uvvqp77rlHd911lyRp4sSJ+uKLL/TOO+/oiSee8Lh0AAAgp1yewA8aAICzZfmkOy4uTqtXr9aQIUOcably5VJUVJSWL1/uYckAAADclxN+XPDiMoyc0K7EdDcm4Jflk+6///5bCQkJCgsLC5geFhamzZs3p/ie2NhYxcbGOq+PHj0qSYqJiXGvoOkg7t8Trq37XHUnJjHTEjMn1JGYxExrTDfjeREzs7QrMbNXTMYJMbNizEffde8A4JhekRkaz4uYKcXLbPzb3szOu5zPLrREJrd3715dfvnlWrZsmSIj/7dhHn/8cS1dulQrV65M9p7hw4drxIgRGVlMAAAAAEA2tGfPHpUpU+ac87P8ke4SJUood+7c2r9/f8D0/fv3Kzw8PMX3DBkyRIMGDXJeJyYm6tChQypevLh8Pp+r5c0oMTExKlu2rPbs2aOQkJBsGTMn1JGYxMyKMXNCHYlJzKwWj5jEzIoxc0IdiZm1mZmOHTum0qVLn3e5LJ9058uXTw0bNtTixYvVtWtXSWeS6MWLF6tfv34pvicoKEhBQUEB04oUKeJySb0REhKS4Z06o2PmhDoSk5hZMWZOqCMxiZnV4hGTmFkxZk6oIzGzrtDQ0Asuk+WTbkkaNGiQevXqpUaNGqlJkyYaO3asTpw44dzNHAAAAAAAL2SLpPuWW27RwYMHNWzYMEVHR6tevXr6+uuvk91cDQAAAACAjJQtkm5J6tev3zlPJ8+JgoKC9MwzzyQ7jT47xcwJdSQmMbNizJxQR2ISM6vFIyYxs2LMnFBHYuYMWf7u5QAAAAAAZFa5vC4AAAAAAADZFUk3AAAAAAAuIekGAAAAAMAlJN0AAAAAALiEpBsAAAAAAJeQdAMAAAAA4BKSbgAAAAAAXELSDQAAAACAS0i6kaLExMRk0xISEojpUsyUphEz7fHMzLV454qZ3dr1XOvPKeMkp+yDMjqeF2Mzu7XruWJ6MU682J5uywzjxIuYOWXfnlNiejE23YzpxThJLyTdCOAfKLlynekaa9as0auvvqqNGzcqd+7cxEzHmBs3btS7776r7du3O9OImfZ4P/zwg5555hn98MMP8vl86R4vpZjZsV1TiplTxkl23Qf5+WNu375d8+bN019//eVKnMwwNrNju0qZY5xkxPb0y8i29Sqml/0np+zbc0pML/a1bsf0J9v+eAsWLNDjjz+u999/P91jucaQ4yUmJgb8e+TIEfv111/tpptuslq1apnP57MxY8YQMw0xExISzMzs2LFjtm3bNuvVq5fVrVvXfD6fTZ06lZipjOd36NAhW7FihXXs2NFq1KhhPp/Pnn766XSLlzRmdm7XpDFzyjjJafugEydO2N69e+3BBx+0hg0bWnBwsM2dOzfd4/ll5NjMzu2aUsyMHCd+XuxrvWjbjBonXtQxp+zbc0pMv4wcmxkV8+x4f//9ty1atMjatGlj1apVM5/PZ4MGDUq2XGaVx+ukH97z/yJ1/Phx/fLLLxo1apSOHDmiUqVK6Z577tF//vMfXXXVVcRMQ8zTp0/r119/1QsvvKBdu3bpsssuU6dOnfTvv/+qfv36xExlvL///ltr1qzRiBEjlJiYqPLly2v48OF6/PHHFRUVlW7xksbMzu2aNGZOGSc5ZR/k8/n022+/acyYMVq/fr1CQkJUr149/fvvv6patWq6x/NibGbndk0a04tx4sX29KJtM3qceFHHnLJvzykxvRibGRXTH+/PP//Uzz//rOHDh6tw4cKqUqWKnn76afXs2VNRUVGun2mTbrzO+pE5vPHGG9atWzcrUaKE9e3b1xYvXmxmZtdff711796dmGkwadIk69mzpxUpUsTuvvtu59frqKgou/vuu4mZSi+99JJde+21Vrp0aRs0aJCtWLHCzMy6d+9uXbp0Sfd4ZjmjXc1yzjjJKfug6dOn24MPPmiFCxe2Hj162AcffGBmZs2bN7d+/fqlezwvxmZOaFczb8aJF9vTi7bN6Jhe1DGn7NtzSkwvxmZGxkxMTLSRI0fa1VdfbRUrVrSnnnrKfvvtNzMzu/vuu619+/bpGs9tJN2wefPmWd26dW3EiBH27bffOtOXL19uzZs3t59//tnM/nfaTFaNOXfu3AyPOXPmTAsLC7PHH3/c5s+f70xfvHixNWvWzDZu3EjMVPjuu++sffv2NmbMGFu2bJkz/ddff7WrrrrKli5dmq7xzLxp1/fffz/DY3oxNnNKPTMqZtJT7d566y3z+XzWr18/+/zzz53pn3/+uTVt2tR27tyZLjH9vBibOaFdzbzZB2XU9vSibb3cnl70Hy++A3mxb/ciZnYem0ktXbo0Q2P++uuv1qtXLxs/frzTP83Mtm7daq1atbIvvvgiXeO5jaQbZmZ29OjRZNPuv/9+a9mypR07dixLxkxMTLS4uLiAaYcOHXI1pj9uUtHR0cmWueuuu+y6666z48ePEzOVTp06lWzaww8/bI0aNUqxb6WG13U0Mzt48GCGx/Rif5BT6ulFzF27diX7UnL77bfbzTffbCdPnkz3eBkxNs+WXds1M+yDvNieGd1n3Yx59rXUfnv27HG1jl59BzqbF/v2jIiZE8bmqVOnkpU9pbq4+d0rPj4+2fwnnnjCatasaUeOHEmXeBmFpDuH2bRpU8DOPKXObGa2ZMkSK1OmjH333Xdmlnznktljfvjhh3bHHXdYZGSkjR492pYsWeLMO336tCsxP/30U+vfv79df/319s4779jmzZudeUnr/PXXX1tYWJitWrWKmBfhl19+sW3btqUYI6nly5dblSpV7OuvvzaztP3y6UW77tixI+D1ueqZnjG9GJs5pZ5exPzyyy9t2LBh9sADD9iXX34Z8AU76XiYM2eOFS9e3NatW5emmF6MzZzQrmbe7IO82J5etG1Gx9y7d6/z/8TExHO2a3rW0YvvQF7s272ImVPG5nvvvWddunSxqlWr2kMPPWSzZs1y5iXtQ+kV88cff3SOlJudu45r1qyxmjVr2uzZs9MUzws8MiwHmT59uiIiIvTMM8/o9OnTkpTs0RD2/x8BsGzZMtWvX18RERGSlOqbFHgRc8aMGerZs6eKFCmiOnXq6O2339bTTz+t8ePHS5Ly5Mmj+Pj4dI357rvv6tZbb9Xhw4eVL18+DRw4UE888YRmz54t6Uyd/c++/OGHH9S6dWtVr15dZkbM83jvvffUoEEDDRs2THv27HFipGTFihUqV66c6tSpI0mpfjSHF+06bdo0VapUSa+//roz7VzjJL1iejE2c0o9vYg5ZcoU3XTTTVqzZo02bdqkzp07a/DgwVq+fLmkM+PB32+/++473XDDDapataoSExOzzNjMCe0qebMP8mJ7etG2GR1z+vTpuvzyy53HGvl8vmTt5e+z6VVHL74DebFv9yJmThmbs2bNUp8+fVSvXj3deOONWr9+vYYPH66hQ4dKCuxD6RFz1qxZatGihV544QUtW7ZM0pk6+rdfUj///LMKFSqkevXqpTqeZzIyw4d3li1bZlWrVrVu3bpZ/vz57dFHH0122pFfTEyM1apVy8aNG5flYsbExFiHDh0CHnvx66+/Wt++fa1GjRo2duxYZ/qRI0fSJeaBAwesWbNm9tZbbznTli5dap06dbKrrrrKuTmKf9nixYvb5MmTiXkBP/30k9WsWdP69OljhQsXtltvvdV2796d4rKnTp2yqKgoe+WVV1Idz8ybdv3uu++sUqVK1qZNG8uXL19AHz3bwYMH0yWmF2Mzp9TTi5i7d++2WrVq2bRp05xpn332mdWqVctuuOGGgKMHe/bsMZ/PZzNmzEh1PC/GZk5oVzNv9kFebE8v2jajY37zzTdWtmxZa9SokRUrVszee+89Z15Kp5qnRx29+A7kxb7di5g5ZWzGxsbarbfeakOHDnWm7dy501588UW77LLL7IknnnCmnzhxIs0x16xZY3Xr1rX77rvPatasaZ07d7Yff/zRmX/2qeZ33HGHPffcc6mO5yWS7hwgLi7O3nnnHevTp4/99ddf9sknn1jevHnP+6Vl3rx5zikbqTklxouYZmb//vuvVatWLWBnYWb2xx9/2IABA6xx48YBNy354osv0hwzJibGKlSoYOPHjw+Yvnr1auvatat16NDBOb3IzAJ2zMRMWXx8vM2dO9f69OljR48etZ9//tmCg4PP+4GzdOlS53SkrFBHszP99cUXX7R77rnHNm/ebK+88or5fL6ALxBnr/f9999PU0wvxmZOqadX+73o6GgrV66cc7qd3zfffGP169e3Hj162J49e5zpb7/9tvP/rDA2c0K7+mX0Psirfa0XbZuRMY8fP26PPPKI3X///bZy5Up75JFHrHDhwudNvJMmaFnlO5AX+3YvYppl/NhMSEjwZGzGxcVZgwYN7J577gmY/vfff9srr7xiFStWtP/+97/O9O+//z5NMZcvX+7s2zdu3GjVq1dPlngn9csvvzint2eV53P7kXTnENu3b7fVq1c7rz/88EPnS0tsbKwz/d9//82yMRMTEy02NtZ69uxpvXr1SnbDkPXr11vLli2T7UjSGvOff/6xFi1a2JNPPmlmgdehLFu2zCpVqmTDhg1Lt5gJCQk5IuaBAwecO36ama1YscL5wNm1a5cz/cSJE+kSz4s6mp3pl/4Pl9jYWHv55ZeTfYHwz0svXuwPcko9vdjv7dy50ypVqmQTJkwwszNt6P8y8vXXX1uhQoUCviSlVUaPTTNvtuWuXbsytF29+Dwxy/jt6UWf9SLmTz/9ZN98842ZnTmS/fDDDydLvM0Cr49NCy++A/nXm9H79oyO6dXYjI6OzvB9rZnZ0KFDrV27dgHXq5uZ/fnnn3bnnXda165d0+2GhsePHw+4Nv/XX391Eu8ffvjBme7Wjf4yEkl3NpfSr0D+XzU/+ugjy5s3rz322GMWHx9v+/fvtxEjRtivv/6a7uVwO2bSevq/jI0fPz7ZDRamTp1q+fPnt7/++itN8c42YcIEy5MnT8DjC/xlevnlly0sLMyOHDmSrr/KvfHGG9kyZko3xfAfzVq5cqXzgfPnn3/agQMHrF+/fgGPP0krL9o1qX///dfGjBkT8AUiOjraxo8ff85ft9PCi/2Bmbv1zCn7vaSGDh1qwcHBzjrj4uKc+IMGDbI6derYyZMn03TTGS/Gptfbcvjw4a6369ky6vPE631tRvTZzBDTb/fu3TZo0CArXLiwzZw508zO7PM+/vjjNN/d2uvvQEll9L7d7ZhJefFdz7+ujNzXLlq0yMqUKWNPPvlksjvBf/bZZ5YrV65kCfmlSmmM+X+A+u2335zEe9myZXbw4EG75ZZbkp2lktWQdGdT//zzz0WdMvTRRx9Zvnz5rF+/fta4cWOrWbPmOe8YeCHffPONTZgwwcaMGWM//fSTM/3sX3HTM+aePXucRyYkHcCjRo2yvHnz2qRJkwI+zObPn2+NGjWyf/75J1XxzALbNmnMBx54wAoUKGALFiwIWP7dd9+15s2bp/hoh4uVtG1XrlzpbNM+ffpkm5hJt2VKfdbfR3766ScrUKCAdevWzerWrWsRERHp0mczql1//PFH+/jjj23atGn2559/OtOTjpOTJ0/amDFjLHfu3DZq1Chr3ry51a5dO9VfBL0Ym17UM6fs95K2rf8LZWxsrHXq1MlKlChh69evD1j+hRdesKioqFTFMvNmbHqxLZMeJffHPnTokHXt2tWVdjXz5vPEi+2Z0X3Wi5irV6+2b7/91r744ouA7ZN0X7Br1y4bNGiQhYaG2sSJE61FixZWp06dVCdpXnwH8mLffjFnsLj5eZJRY/Orr76yESNG2OOPP26ffPKJ0y/8486Nsbl582anjyRdx1tvvWW5cuWyoUOHOs+NNztzDXb9+vVt+/btaY6X0rbxT1u3bp1FRERYhw4drFq1alajRo10OyvEKyTd2dD06dPtqquusmXLll3Ujnzy5Mnm8/mscePGzi9pl7qTevvtt61QoULWrl07K1asmNWtW9fuvPNOZz1nD5T0iDljxgyrVauWzZgxwzmFKOkOY9iwYebz+eyxxx6zuXPn2u+//27t2rWza665JtUfcCm1rf/ff/75x/r06WP58uWzN954w1auXGn79u2ztm3bWufOnVMdM6W27dWrl9NevXr1yvIxU9qW5zvC9fXXX5vP57OmTZs6/edSP3C8aNfJkydbSEiINW3a1PLmzWuNGze24cOHO+tLOk5iY2NtxIgR5vP5rFGjRk49LzW2F2PTi3rmlP3e2W3bqFEjGzFihJmdOZJ27bXXWkhIiH3++ee2fft2O3r0qEVFRdmtt956SXH8vBibXmzLadOmWZcuXQIe7+S3bt0669y5c7q2q5k3nydebM+M7rNexJw0aZIVL17catasaT6fz1q1amVTpkxx5ifdF/z555/2wAMPmM/ns4YNG6Z6n+fFdyAv9u3nG5tnc/PzxO2xOWXKFMufP7/dcsstVq1aNatZs6a1bt3a+cHBv23Tc2zOmDHDLr/8cnv22Wed07eTbsMJEyZY0aJF7fbbb7fJkyfbihUrrG3btta8efNU/ZiRUrzz7X+WLFmS5jpmJiTd2cxXX31lJUuWtODgYGvQoIH99NNP590BHDhwwJo0aWL169d3Btql/pK0fft2q1ixok2dOtXMzlyf8Z///Mfq1Klj11xzjTN4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yBHnS33SR/+YnWn78uXLW5s2bWzdunXWrFkzu/3221Md04t6Ju2z/iODZyf9bn1uZuT+IGnb+sv9888/W1BQkD344IPpHjNp//GPmdmzZzt3zfbzt3WnTp3SnOR7PTYzol3NvBmbXnyeHD161Pm/fx07d+60Zs2aWbt27ZLdGf21116zq6++Ok3Pxk4a82xJz7zo27evNWnSxIYOHWqRkZFWuXLlVH2OZXS8rICkOwubPHmylS1b1kqXLm0VKlSwa665xn777TczC/yFzuxMB/ffVbNmzZqpvtnDJ598Yn369LEtW7Y40/w7pbVr11qRIkWsc+fO9vnnn1t8fLwdPnzYrrrqKnvggQdSXc+UYp4t6VGD9u3bm8/nszp16qS6njm5bd2M6cW2nDRpkoWHh1vFihWtfPnyVqVKFVu4cKFrdTRL3n/atGlja9asMTOzOXPmWL58+axHjx7266+/WmJiop08edKaNGligwcPTnVML/qPF/X0YmzmhD7kxdj87LPP7LnnnjvvzZHSe1u+8847VqVKFQsPD7fKlSvbPffcY7///rsTI+k6t23bZhUqVDCfz2fVq1cPuMbxUnhRz5T67NlH6t3+3MyI/UFKbevfjnPnzrWgoKB0jZm0/1SpUiVgzIwdO9Zy5cplgwcPtr///tvMziRr9evXt+effz7VdcwsY9PNdjXzZmx68XnywQcf2DXXXOMcNfcf6TY78yN5gwYNLCoqyt544w2LjY21ffv22TXXXGN33HFHquqYUsyUJG3j3r17m8/nswYNGqTqpmkZHS+rIOnOor777jsrVKiQTZ8+3bZv324zZ860zp07W6FChQKu8zE703FjY2OtefPmduWVV6b6LoCfffaZ5c6d2y6//HIbMGCAbd261czODBj/utavX28tWrSwWrVq2eWXX24NGza02rVrp+nLSkoxU5KQkGAnT560Fi1aWLNmzVJdz5zetm7F9GJbrly50ooUKWKzZs2ygwcP2g8//GB33nmn5c6d29555x0zM/vtt9+sefPm6dau5+o/BQsWdK4TW7JkiROrVq1aFhkZaTVr1kz1dUte9B8v6unF2MwJfciLsTl79mzz+XxWvHhxGzNmjHOq6Llipse2XLhwoRUsWNAmTZpka9eutdGjR9s111xj1apVc75oJz3CcvjwYatXr541b948S9XzXH02T548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04uYXrTtuWKe6xfCrNi2XmxL/zWMl112mb322mvO9KTb8tlnn7WmTZtaWFiY3XLLLdaoUaM03W01p/efm266yfkif++991q9evVc3we5GTMn9CEv+s/HH39swcHB9uabb9pLL71kffv2tdy5c9ujjz4a8KXdHzM2NtaKFy+epjsEnyvmQw895CwTFRVltWrVsi5dutioUaOsVatWVqdOnTRdN5nR9fSiz3oxNjO6bb3oP4zNh5xl0rttM9PnybmS0mPHjlmlSpWsadOm6b4/cCumF3XM6ki6M7FffvnFGjVqZPfcc4/deuut1rx5c5sxY4YzP+kH69y5c23AgAF266232sMPP5zqu2Wanbn7Zbdu3QKmLV++3AoXLmw33nijc71PYmKiHT9+3Bo0aGAVKlRI0yDK6JhetO2FYp69o8qqbZvR8fyPwurbt689+uijVq1aNRszZowzP+m2XLt2rT377LPWv39/Gz58uGvbMqf0n65duzr1mDNnTobsg9yImRP6kFf957777rN77rnHef3vv//a+++/b/nz5w/4op2YmGhHjx61Ro0aWcWKFV2LmfSU2Ndff926d+9u1157rfXp0yfgebzpGdONenrRZ8282R9kdNtmdP9hbLo7NjPb58nZ2/PkyZPWoUMHu+KKK1J9B++MjulFHbMDku5M7Pfff7fu3bvbpk2bbP369XbrrbdaixYtAnbG5zu951I7tP/XqB49eliHDh2Sxfj555+tYMGCNnjw4ID3ffDBB6keRF7ENMv4tr3YmGefTpaV2tarbfnXX3/ZXXfdZb/88ov9+eefNnjw4GQfAF5sy5zSf853bWhWiGmWM/pQRvcfszNfVqOioqxHjx7JYnz88ceWO3fugCMkZmdOm3U75tmnVidt56xSz4zus16NzYxuWy/6D2PTnbbNzJ8nZyelX3zxhev7g/SM6UUdswOS7kzGv5Pw/+u/U6TZmV9DU9oZHz9+PF3L8PHHH1tQUFDAXRv9A2T69OlWrFgx5/mFSaVlEGVETC/aNjUxk97Mwy+zt61X8fzt6j9FzOzM3XlT+gA4evRosi8uqYlF/0m+Pc/3KJDMHjM79yEv+s/Z7TN+/HgrVaqU8wgiv4SEBHvuuecsIiIi2V1sMyJmSncHvpRt60U9z46dEX32bBkxNjO6bb3sP4zN5DHT2rZny6yfJzExMcnq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zjslSYmJiRo9erQqVqyo/Pnzq27duvr444+dMvhjfPXVV2rYsKGCgoL0ww8/nLPevXr10qxZs/Tvv/8609555x316tUr2bJ79uzRzTffrCJFiqhYsWLq0qWLdu7c6cxftWqV2rZtqxIlSig0NFQtW7bUmjVrnPlmpuHDh6tcuXIKCgpS6dKlNWDAAGd+Smc7FClSRFOnTpV05ocin8+nDz74QC1btlRwcLDee++9C24b//s+/PBDXXXVVcqfP78aN26s33//XatWrVKjRo1UqFAhdejQQQcPHgyIfzHrnT17tlq3bq0CBQqobt26Wr58ubMt7rrrLh09etQ5qyBpvwcAeMQAAHDZP//8Yz6fz55//vnzLpeQkGD16tWzFi1a2M8//2wrVqywhg0bWsuWLZ1levXqZV26dAl430MPPRSwTMuWLS0kJMSGDx9uv//+u7377rvm8/lswYIFZmZ24MABk2RTpkyxffv22YEDB8zM7JlnnrG6desGxAoJCbH777/fNm3aZHPnzrUCBQrYW2+95SwTFRVl9erVsxUrVtjq1autZcuWlj9/fnvttdfOWc+z4+zYscNq1qxpYWFhzrQZM2ZYqVKl7JNPPrHt27fbJ598YsWKFbOpU6eamdnRo0etWLFi1qNHD9uwYYN9+eWXVrVqVZNkv/zyi5mZffvttybJDh8+bGZmHTt2tLZt29pvv/1mf/zxh82dO9eWLl1q8fHx9sknn5gk27Jli+3bt8+OHDliZmajRo2y6tWr29dff21//PGHTZkyxYKCgmzJkiUBMerUqWMLFiywbdu22T///JNivSXZp59+anXq1LHp06ebmdmuXbssKCjIfv/9d5Nk3377rZmZxcXFWY0aNezuu++23377zTZu3Gi33XabVatWzWJjY83MbPHixTZ9+nTbtGmTbdy40Xr37m1hYWEWExNjZmYfffSRhYSE2Jdffmm7du2ylStXBmw7f3mSCg0NtSlTpjjbRZJVqFDB2Q579+694Lbxv8/fbhs3brRmzZpZw4YNrVWrVvbDDz/YmjVrrEqVKnb//fdf9DZPut558+bZli1b7MYbb7Ty5cvb6dOnLTY21saOHWshISG2b98+27dvnx07duyc/RAAkDFIugEArlu5cqVJstmzZ593uQULFlju3Llt9+7dzrQNGzaYJPvpp5/M7OKT7hYtWgQs07hxYxs8eLDzOqWEK6Wku3z58hYfH+9Mu+mmm+yWW24xM7NNmzaZJFu1apUzf+vWrSbpgkl3rly5rGDBghYcHGySTJK9+uqrzjKVK1e2mTNnBrzv2WeftcjISDMzmzBhghUvXtz+/fdfZ/6kSZPOm3TXrl3bhg8fnmKZzl7WzOzUqVNWoEABW7ZsWcCyvXv3tltvvTXgfXPmzDlnff38bT527Fhr3bq1mZmNGDHC/u///s8OHz4ckHRPnz7dqlWrZomJic77Y2NjLX/+/DZ//vwU15+QkGCFCxe2uXPnmpnZK6+8YlWrVrW4uLjzlieplJLusWPHBixzoW3jf9/kyZOd+e+//75JssWLFzvTRo8ebdWqVUvTev3jY9OmTWZmNmXKFAsNDU2xvgAAb3BNNwDAdWZ2Uctt2rRJZcuWVdmyZZ1pERERKlKkiDZt2qTGjRtfdMw6deoEvC5VqpQOHDhw0e/3q1mzpnLnzh2wnnXr1kmStmzZojx58qhBgwbO/CpVqqho0aIXXG+1atX0+eef69SpU5oxY4bWrl2r/v37S5JOnDihP/74Q71799Y999zjvCc+Pt65KdqWLVtUp04dBQcHO/ObNGly3pgDBgzQAw88oAULFigqKkrdunVL1k5Jbdu2TSdPnlTbtm0DpsfFxal+/foB0xo1anTBOvv16NFDTzzxhLZv366pU6fq9ddfT7bMr7/+qm3btqlw4cIB00+dOqU//vhDkrR//349/fTTWrJkiQ4cOKCEhASdPHlSu3fvliTddNNNGjt2rCpVqqRrr71W1113nTp37nzO683PJWndLmbb+CVt27CwMElS7dq1A6b5+2Rq11uqVClJ0oEDB1S9evVLqhcAIGOQdAMAXHfFFVfI5/Oly83ScuXKlSyJT3qNtd/ZN7vy+XxKTEy85HjptZ6z5cuXT1WqVJEkvfDCC+rYsaNGjBihZ599VsePH5ckTZo0SU2bNg14X9IfAC5Vnz591L59e33xxRdasGCBRo8erVdeecVJ9s/mL8cXX3yhyy+/PGBeUFBQwOuCBQtedDmKFy+uTp06qXfv3jp16pQ6dOigY8eOJYvdsGFD5xrqpC677DJJZ64P/+eff/Sf//xH5cuXV1BQkCIjIxUXFyfpzE3btmzZokWLFmnhwoV68MEH9fLLL2vp0qXKmzevfD7fRfWlpHW7lG2TtO/4fL4Up/n7UlrXmx59EgDgDm6kBgBwXbFixdS+fXuNGzdOJ06cSDbff6OvGjVqaM+ePdqzZ48zb+PGjTpy5IgiIiIknUm49u3bF/B+/43DLkXevHmVkJBwye9Lqlq1aoqPj9cvv/ziTNu2bZsOHz58yet6+umnNWbMGO3du1dhYWEqXbq0tm/fripVqgT8VaxY0Ym9bt06xcbGOutYtWrVBeOULVtW999/v2bPnq1HHnlEkyZNknTmRwBJAW0SERGhoKAg7d69O1k5kp6NkBp33323lixZop49e6b4Q0KDBg20detWlSxZMlls/5HfH3/8UQMGDNB1112nmjVrKigoSH///XfAevLnz6/OnTvr9ddf15IlS7R8+XLnTIWz+9LWrVt18uTJ85b7YrZNaqTXevPly5fmfg0ASF8k3QCADDFu3DglJCSoSZMm+uSTT7R161Zt2rRJr7/+uiIjIyVJUVFRql27tm6//XatWbNGP/30k3r27KmWLVs6p/i2adNGP//8s6ZNm6atW7fqmWee0fr16y+5PBUqVNDixYsVHR2dqiRZkqpXr66oqCjde++9+umnn/TLL7/o3nvvVf78+Z0jkBcrMjJSderU0fPPPy9JGjFihEaPHq3XX39dv//+u9atW6cpU6bo1VdflSTddtttSkxM1L333qtNmzZp/vz5GjNmjCSdM/bAgQM1f/587dixQ2vWrNG3336rGjVqSJLKly8vn8+nefPm6eDBgzp+/LgKFy6sRx99VA8//LDeffdd/fHHH1qzZo3eeOMNvfvuu6lqM79rr71WBw8e1MiRI1Ocf/vtt6tEiRLq0qWLvv/+e+3YsUNLlizRgAED9Oeff0o6cwbF9OnTtWnTJq1cuVK333678ufP76xj6tSpevvtt7V+/Xpt375dM2bMUP78+VW+fHlJZ/rSm2++qV9++UU///yz7r///ot6HNiFtk1qpcd6K1SooOPHj2vx4sX6+++/L/gjAgDAfSTdAIAMUalSJa1Zs0atW7fWI488olq1aqlt27ZavHixJkyYIOlMsvjZZ5+paNGiuvrqqxUVFaVKlSoFPLu6ffv2Gjp0qB5//HE1btxYx44dU8+ePS+5PK+88ooWLlyosmXLJrs++VJMmzZNYWFhuvrqq/V///d/uueee1S4cOGAa60v1sMPP6zJkydrz5496tOnjyZPnqwpU6aodu3aatmypaZOneoc9QwJCdHcuXO1du1a1atXT0899ZSGDRsmSeeMnZCQoL59+6pGjRq69tprVbVqVeeRVJdffrlGjBihJ554QmFhYerXr58k6dlnn9XQoUM1evRo531ffPFFmo7qSme2dYkSJZwj7GcrUKCAvvvuO5UrV0433HCDatSo4ZyOHhISIkl6++23dfjwYTVo0EB33HGHBgwYoJIlSzrrKFKkiCZNmqTmzZurTp06WrRokebOnavixYtLOtMHypYtq6uuukq33XabHn30URUoUOCCZb/Qtkmt9FjvlVdeqfvvv1+33HKLLrvsMr300ktpKhMAIO18drF3twEAABf0559/qmzZslq0aJGuueaaDI393nvvOc9pTnrEFwAAeIcbqQEAkAbffPONjh8/rtq1a2vfvn16/PHHVaFCBV199dWux542bZoqVaqkyy+/XL/++qsGDx6sm2++mYQbAIBMhKQbAIA0OH36tJ588klt375dhQsX1pVXXqn33nvvoq4NTqvo6GgNGzZM0dHRKlWqlG666SY999xzrscFAAAXj9PLAQAAAABwCTdSAwAAAADAJSTdAAAAAAC4hKQbAAAAAACXkHQDAAAAAOASkm4AAAAAAFxC0g0AAAAAgEtIugEAAAAAcAlJNwAAAAAALiHpBgAAAADAJf8P/0rm0nK+JA4AAAAASUVORK5CYII=", + "image/png": "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opYtWyaBgYHSsGHDVMc3atRIAgMDZdmyZS7Nf+rUqVKmTBkZOnSoTJgwQQICAuSVV16RyZMnp5j22LFj8uSTT0rz5s1lwoQJUrhwYenevbvs37/fKEv//v1FRGTo0KHGZchVqlRxqWz9+vWTo0ePyqhRo+Txxx+XL774QoYNGyZt27aVhIQE+e9//ysNGjSQcePGyezZs+85r40bN8rly5fl2WeflZw5c9439oULF+Thhx+WlStXyiuvvCLvvfee3LlzRx5//HFZvHixS/UREbly5Yo8+uijUq1aNZkwYYJUrlxZBg8eLD/99JOIiFSpUkVGjx4tIiK9e/c2lmGjRo3uOd958+bJuHHj5MUXX5QxY8bIqVOn5IknnpC4uDhjmh9//FGefvppyZ07t4wdO1aeeOIJ6dGjh+zcudPl+oj8X2KcNAl87733pGvXrvLQQw/JxIkTZcCAAbJ27Vpp1KiRXL16VUTuJnMtW7aULVu2SL9+/WTy5MnSu3dvOXHihDFNRkyaNElKlSollStXNpbj22+/LSJ3f4AaNWqUNG3aVD777DN5++23pXTp0rJr1657znPnzp0SGxsrNWvWTHOat99+W+Lj4+X999+/57zi4uLk0qVL6fpLes98kyZNJDo6Wl588UU5ePCgnD59Wj7//HNZtGiRDBkyxIkllFJgYKCEh4fLN998Ywz76aef5Nq1a9KpU6dUv3PlypV01eHWrVv3jR8ZGSn58uWTfPnyOQz39fWV8uXLy++//56h+gFApsrsU+0AgJSuXr2qIqLt2rW753SPP/64iohGR0erqmq3bt20TJkyKaYbMWKEJu/yb926lWK6li1barly5RyGlSlTRkVEf/31V2NYVFSUenl56euvv24Mu9fl5SKiI0aMSDG8TJky2q1bN+Oz/VLXli1bOlwGHh4erjabTV966SVjWHx8vJYqVeq+lxB//PHHKiK6ePHie05nN2DAABUR/e2334xh169f17Jly2pgYKAmJCQ4lDXpJc2q/3c5cdLl0LhxYxURnTVrljEsJiZG/f39tUOHDsawe11ennzdnjx5UkVEixYtqpcvXzaGL126VEVEly1bZgwLCQnRUqVK6fXr141h69evVxFJtb0k17hxY61cubJevHhRL168qIcOHdI333xTRcThkuNTp05pzpw59b333nP4/t69ezVXrlzG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c4zxSXemy5Yt0/79++szzzyjr732mtNP2r5fndq3b2/Ma8mSJRmKZcWyU1V98cUXtVevXsbn27dv6zfffKN58+Z1uDznk08+0U6dOumjjz6qPXv2dHi/5/1YtY7sr6Po06ePvvHGG1qpUiUdP358qnF2796t7777rvbr109Hjhzp1vXjrnZwv+WWfIdgVjtIerCTmJio165d01q1amnZsmVd2uFYEcuqtuCJbduKPuF+9Unetm/duqWtWrXShx56yKmn6lq5DalmjX7Bnfs8T2oLnrZ/ULWu37bqeOR+dcpubc6q/sfKfi4rHJu6s21b1RY8BUl3FmT/Nahz587aqlUrY7i9ge7YsUPz58+f4kX13377rdON+MiRI9qpUyc9ePCg7tu3T5955hlt0KCBQ4dzr8tM0hsnvXW6131f6Yll5bKLj4/XiIgI7dy5c4r4CxYs0Jw5c6a4pC7pssxq6+jvv//W559/Xv/44w/966+/dPDgwSk60IzGsaodqKZvuSW/fMysdpD011/Vu5eMubLDsSqWFW1B1bPatqp1fUJ66pP8YOfHH380Zf/gjm0oq/ULtAXX4mSn/YMVfamVxyPprVN2anNW9T9WxMlqx6buOiaxqi14CpLuLGzBggXq5eXl8FRWewOdPXu2FilSxHg/aVL3a8T2jc/+r/2Jhap3f/FLrcO5ceOG6xVJIj11uterJdwZJyPLzm7KlClaokQJ4xUMdgkJCfree+9pUFBQqk9mTD6ftMZbtY7sceyX7qnefepsah3otWvX7lv++zGrHbiy3JI+jCd5We4Xxy497SD501rTE8fqWEnjmdUWPK1tW9UnJJ8uPfWJjo5OMV8z9g+ubEOpyUr9gittztPagitxssP+wc7svtTOrOMRVc9rc1bvw63u57LSsWlG27ZV/Y8nIenOYpI2wsjISO3cubM2aNBAN27cqKr/18j37dunxYsX17Vr1zodI7XLhxITE41fo3bv3q2dOnXSBg0a6Lx58/TmzZsaFhamCxcudKVKltTJqjjJl93u3bu1efPm+txzz6V43ca6devU19dXd+3aleE4quato9Q6PnucU6dO6aBBg7RSpUo6ceJEvXPnjtauXVv/97//ZShOdm/bVrUDq2NZ0RY8rW2zfrL+/sET+4XM6LetipPd99+q1h33eFqby6xt1aw4qp7XtlWt6xc8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", "text/plain": [ "
" ] @@ -480,9 +549,16 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "e1f273c0", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-26T21:20:51.568418Z", + "iopub.status.busy": "2026-02-26T21:20:51.568045Z", + "iopub.status.idle": "2026-02-26T21:20:52.392208Z", + "shell.execute_reply": "2026-02-26T21:20:52.390984Z" + } + }, "outputs": [ { "name": "stdout", @@ -515,13 +591,13 @@ ")\n", "\n", "device = LocalSimulator()\n", - "task_3 = device.run(circ_3, shots=1000)\n", + "task_3 = run_quantum_counting(circ_3, device, shots=1000)\n", "\n", "results_3 = get_quantum_counting_results(\n", " task_3, counting_qubits_3, search_qubits_3, verbose=True\n", ")\n", "\n", - "print(f\"\\nActual M = 0\")\n", + "print(\"\\nActual M = 0\")\n", "print(f\"Estimated M = {results_3['best_estimate']:.4f}\")" ] }, @@ -539,7 +615,14 @@ "cell_type": "code", "execution_count": 10, "id": "36cbb24d", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-26T21:20:52.395277Z", + "iopub.status.busy": "2026-02-26T21:20:52.395041Z", + "iopub.status.idle": "2026-02-26T21:20:53.461638Z", + "shell.execute_reply": "2026-02-26T21:20:53.460245Z" + } + }, "outputs": [ { "name": "stdout", @@ -572,7 +655,7 @@ ")\n", "\n", "device = LocalSimulator()\n", - "task_4 = device.run(circ_4, shots=1000)\n", + "task_4 = run_quantum_counting(circ_4, device, shots=1000)\n", "\n", "results_4 = get_quantum_counting_results(\n", " task_4, counting_qubits_4, search_qubits_4, verbose=True\n", @@ -589,7 +672,7 @@ "source": [ "## [Optional] Run on a QPU or Managed Simulator\n", "\n", - "**Note:** The current implementation uses `Circuit.unitary()` for the controlled-Grover operations within QPE. This gate-synthesis approach works on simulators but is **not directly compatible with QPU execution**, which requires circuits decomposed into native gate sets. To run on a QPU, the controlled-Grover operator would need to be fully decomposed into native one- and two-qubit gates.\n", + "**Note:** The current implementation builds the controlled-Grover operator from **gate-level primitives** (controlled-H gates and controlled MCZ oracles), rather than using `Circuit.unitary()`. This circuit-based approach is more compatible with QPU execution since it uses native one- and two-qubit gates. However, the circuit depth grows exponentially with the number of counting qubits (as is inherent in QPE), which may exceed the coherence limits of current hardware for larger problem sizes.\n", "\n", "[Include estimated price for running in USD using the [cost tracker](https://docs.aws.amazon.com/braket/latest/developerguide/braket-pricing.html#real-time-cost-tracking).]" ] @@ -598,7 +681,14 @@ "cell_type": "code", "execution_count": 11, "id": "690a8210", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-26T21:20:53.465560Z", + "iopub.status.busy": "2026-02-26T21:20:53.465069Z", + "iopub.status.idle": "2026-02-26T21:20:53.473632Z", + "shell.execute_reply": "2026-02-26T21:20:53.471814Z" + } + }, "outputs": [], "source": [ "# Use Braket SDK Cost Tracking to estimate the cost to run this example\n", @@ -611,7 +701,14 @@ "cell_type": "code", "execution_count": 12, "id": "2c70f923", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-26T21:20:53.477667Z", + "iopub.status.busy": "2026-02-26T21:20:53.477363Z", + "iopub.status.idle": "2026-02-26T21:20:53.486847Z", + "shell.execute_reply": "2026-02-26T21:20:53.481010Z" + } + }, "outputs": [], "source": [ "# from braket.aws import AwsDevice, AwsSession\n", @@ -636,7 +733,7 @@ "# circ, counting_qubits, search_qubits, marked_states\n", "# )\n", "\n", - "# task = managed_device.run(circ, shots=1000)\n", + "# task = run_quantum_counting(circ, managed_device, shots=1000)\n", "\n", "# results = get_quantum_counting_results(\n", "# task, counting_qubits, search_qubits, verbose=True\n", @@ -648,7 +745,14 @@ "cell_type": "code", "execution_count": 13, "id": "1c2e7121", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-26T21:20:53.490298Z", + "iopub.status.busy": "2026-02-26T21:20:53.489933Z", + "iopub.status.idle": "2026-02-26T21:20:53.494046Z", + "shell.execute_reply": "2026-02-26T21:20:53.492842Z" + } + }, "outputs": [], "source": [ "# print(\"Task Summary\")\n", diff --git a/src/braket/experimental/algorithms/quantum_counting/__init__.py b/src/braket/experimental/algorithms/quantum_counting/__init__.py index a9945f49..afc94115 100644 --- a/src/braket/experimental/algorithms/quantum_counting/__init__.py +++ b/src/braket/experimental/algorithms/quantum_counting/__init__.py @@ -16,4 +16,5 @@ build_oracle_circuit, get_quantum_counting_results, quantum_counting_circuit, + run_quantum_counting, ) diff --git a/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py b/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py index 78c0e373..c9bc4049 100644 --- a/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py +++ b/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py @@ -16,7 +16,9 @@ from braket.circuits import Circuit from braket.circuits.qubit_set import QubitSetInput +from braket.devices import Device from braket.experimental.algorithms.grovers_search.grovers_search import amplify, build_oracle +from braket.tasks import QuantumTask def build_oracle_circuit( @@ -66,11 +68,6 @@ def build_grover_circuit( Uses circuit primitives from grovers_search: build_oracle for the phase oracle and amplify for the diffusion operator (H · oracle_0 · H). - Note: - The MCZ ancilla decomposition introduces a global phase of -1 - relative to the ideal Grover matrix. This is accounted for - in get_quantum_counting_results during phase correction. - Args: n_qubits (int): Number of qubits in the search register. marked_states (List[int]): Indices of marked states. @@ -88,6 +85,164 @@ def build_grover_circuit( return grover_circ +def _controlled_oracle_circuit( + control: int, + search_qubits: QubitSetInput, + marked_states: List[int], + decompose_ccnot: bool = False, +) -> Circuit: + """Build a controlled oracle circuit using gate-level primitives. + + Makes the phase-flip oracle controlled on the given qubit by prepending + "1" to each marked-state bitstring, so the MCZ gate gains an extra + control qubit. + + Args: + control (int): Index of the control qubit. + search_qubits (QubitSetInput): Indices of the search register qubits. + marked_states (List[int]): Indices of marked computational-basis states. + decompose_ccnot (bool): Whether to decompose CCNOT (Toffoli) gates. + + Returns: + Circuit: Controlled oracle circuit. + """ + n_search = len(search_qubits) + circ = Circuit() + + for state in marked_states: + bitstring = format(state, f"0{n_search}b") + # Prepend "1" so the MCZ is controlled on the QPE qubit + controlled_bitstring = "1" + bitstring + oracle_sub = build_oracle(controlled_bitstring, decompose_ccnot) + # Map the oracle qubits: qubit 0 -> control, qubits 1..n -> search_qubits + target_mapping = [control] + list(search_qubits) + # The oracle may use ancilla qubits beyond n_search+1; they are + # automatically placed by add_circuit's target mapping. + all_targets = target_mapping + list( + range( + max(target_mapping) + 1, + max(target_mapping) + 1 + oracle_sub.qubit_count - len(target_mapping), + ) + ) + circ.add_circuit(oracle_sub, target=all_targets) + + return circ + + +def _controlled_diffusion_circuit( + control: int, + search_qubits: QubitSetInput, + decompose_ccnot: bool = False, +) -> Circuit: + """Build a controlled diffusion (amplitude amplification) circuit. + + The diffusion operator is D = H^⊗n · O_0 · H^⊗n, where O_0 flips the + phase of the |0⟩ state. To make it controlled: + - H gates become controlled-H (CH) gates + - O_0 becomes controlled by prepending "1" to the "00...0" bitstring + + Args: + control (int): Index of the control qubit. + search_qubits (QubitSetInput): Indices of the search register qubits. + decompose_ccnot (bool): Whether to decompose CCNOT (Toffoli) gates. + + Returns: + Circuit: Controlled diffusion circuit. + """ + n_search = len(search_qubits) + circ = Circuit() + + # First set of controlled-H gates on search qubits + for sq in search_qubits: + _add_controlled_h(circ, control, sq) + + # Controlled O_0: flip phase of |0⟩, controlled on QPE qubit + # O_0 uses build_oracle("00...0"). Controlled version: build_oracle("1" + "00...0") + controlled_zero_bitstring = "1" + "0" * n_search + zero_oracle = build_oracle(controlled_zero_bitstring, decompose_ccnot) + target_mapping = [control] + list(search_qubits) + all_targets = target_mapping + list( + range( + max(target_mapping) + 1, + max(target_mapping) + 1 + zero_oracle.qubit_count - len(target_mapping), + ) + ) + circ.add_circuit(zero_oracle, target=all_targets) + + # Second set of controlled-H gates on search qubits + for sq in search_qubits: + _add_controlled_h(circ, control, sq) + + return circ + + +def _add_controlled_h(circ: Circuit, control: int, target: int) -> None: + """Add a controlled-Hadamard gate to the circuit. + + Decomposition: CH(c, t) = S†(t) · H(t) · T†(t) · CX(c,t) · T(t) · H(t) · S(t) + + Args: + circ (Circuit): Circuit to append the controlled-H to. + control (int): Control qubit index. + target (int): Target qubit index. + """ + circ.s(target) + circ.h(target) + circ.t(target) + circ.cnot(control, target) + circ.ti(target) + circ.h(target) + circ.si(target) + + +def controlled_grover_circuit( + control: int, + search_qubits: QubitSetInput, + marked_states: List[int], + power: int = 1, + decompose_ccnot: bool = False, +) -> Circuit: + """Build a controlled Grover operator G^power as a gate-level circuit. + + Constructs the controlled Grover operator C-G = C-D · C-O entirely from + gate-level primitives: + - The oracle is made controlled by prepending "1" to each marked-state + bitstring, adding the control qubit as an extra MCZ control. + - The diffusion operator is made controlled by using controlled-H (CH) + gates and a controlled zero-oracle. + + Note: + The MCZ ancilla decomposition introduces a global phase of -1 on + the Grover operator. This phase is inherent in the circuit-based + controlled construction and is corrected during post-processing + in get_quantum_counting_results. + + Args: + control (int): Index of the QPE control qubit. + search_qubits (QubitSetInput): Indices of the search register qubits. + marked_states (List[int]): Indices of marked computational-basis states. + power (int): Number of times to apply the Grover operator (default 1). + decompose_ccnot (bool): Whether to decompose CCNOT (Toffoli) gates. + + Returns: + Circuit: Circuit implementing the controlled G^power operator. + """ + circ = Circuit() + + for _ in range(power): + # Controlled oracle + circ.add_circuit( + _controlled_oracle_circuit(control, search_qubits, marked_states, decompose_ccnot) + ) + + # Controlled diffusion + circ.add_circuit( + _controlled_diffusion_circuit(control, search_qubits, decompose_ccnot) + ) + + return circ + + def inverse_qft_for_counting(qubits: QubitSetInput) -> Circuit: """Inverse Quantum Fourier Transform applied to the given qubits. @@ -114,32 +269,6 @@ def inverse_qft_for_counting(qubits: QubitSetInput) -> Circuit: return qft_circ -def controlled_grover( - control: int, target_qubits: QubitSetInput, grover_unitary: np.ndarray -) -> Circuit: - """Apply a controlled Grover operator. - - Applies the controlled-U gate where U is the Grover operator, with the - given control qubit and target qubits. - - Args: - control (int): Index of the control qubit. - target_qubits (QubitSetInput): Indices of target (search and ancilla) qubits. - """ - circ = Circuit() - - # Build controlled unitary: |0><0| ⊗ I + |1><1| ⊗ U - p0 = np.array([[1.0, 0.0], [0.0, 0.0]]) - p1 = np.array([[0.0, 0.0], [0.0, 1.0]]) - id_matrix = np.eye(len(grover_unitary)) - controlled_matrix = np.kron(p0, id_matrix) + np.kron(p1, grover_unitary) - - targets = [control] + list(target_qubits) - circ.unitary(matrix=controlled_matrix, targets=targets) - - return circ - - def quantum_counting_circuit( counting_circ: Circuit, counting_qubits: QubitSetInput, @@ -149,8 +278,8 @@ def quantum_counting_circuit( ) -> Circuit: """Create the full quantum counting circuit with result types. - Builds the Grover operator as a circuit from grovers_search primitives - (build_oracle + amplify), extracts its unitary, and applies QPE. + Builds the controlled Grover operator as a gate-level circuit and + applies QPE. Args: counting_circ (Circuit): Initial circuit (may contain setup operations). @@ -179,20 +308,18 @@ def quantum_counting( ) -> Circuit: """Build the core quantum counting circuit using QPE on the Grover operator. - Constructs the Grover operator as a gate-level circuit from grovers_search - primitives (build_oracle for the phase oracle, amplify for the diffusion - operator), extracts its unitary via Circuit.to_unitary(), and applies - controlled-G^(2^k) for QPE. + Constructs the controlled Grover operator as a gate-level circuit from + grovers_search primitives (build_oracle for the phase oracle and + controlled-H gates for the diffusion operator). Note: The MCZ ancilla decomposition in grovers_search introduces a global phase of -1 on the Grover operator relative to the ideal matrix. - This shifts QPE phase estimates by 0.5. The correction is applied - in get_quantum_counting_results. + This phase shift is corrected in get_quantum_counting_results. The circuit structure: 1. Apply H to all counting qubits - 2. Apply H to all search qubits (prepare uniform superposition |s>) + 2. Apply H to all search qubits (prepare uniform superposition |s⟩) 3. Apply controlled-G^(2^k) for each counting qubit k 4. Apply inverse QFT to counting qubits @@ -205,33 +332,22 @@ def quantum_counting( Returns: Circuit: Circuit implementing the quantum counting algorithm. """ - n_search = len(search_qubits) - - # Build the Grover operator circuit from grovers_search primitives - grover_circ = build_grover_circuit(n_search, marked_states, decompose_ccnot) - grover_unitary = grover_circ.to_unitary() - - # Determine ancilla qubits introduced by the circuit decomposition - n_ancilla = grover_circ.qubit_count - n_search - ancilla_qubits = [ - max(list(counting_qubits) + list(search_qubits)) + 1 + i - for i in range(n_ancilla) - ] - all_grover_qubits = list(search_qubits) + ancilla_qubits - qc_circ = Circuit() # Hadamard on counting qubits qc_circ.h(counting_qubits) - # Hadamard on search qubits (prepare |s>) + # Hadamard on search qubits (prepare |s⟩) qc_circ.h(search_qubits) # Controlled-G^(2^k) for ii, qubit in enumerate(reversed(counting_qubits)): power = 2**ii - g_power = np.linalg.matrix_power(grover_unitary, power) - qc_circ.add_circuit(controlled_grover(qubit, all_grover_qubits, g_power)) + qc_circ.add_circuit( + controlled_grover_circuit( + qubit, search_qubits, marked_states, power, decompose_ccnot + ) + ) # Inverse QFT on counting qubits qc_circ.add_circuit(inverse_qft_for_counting(counting_qubits)) @@ -239,6 +355,24 @@ def quantum_counting( return qc_circ +def run_quantum_counting( + circuit: Circuit, + device: Device, + shots: int = 1000, +) -> QuantumTask: + """Run the quantum counting circuit on a device. + + Args: + circuit (Circuit): The quantum counting circuit to run. + device (Device): Braket device backend. + shots (int): Number of measurement shots (default is 1000). + + Returns: + QuantumTask: Task from running quantum counting. + """ + task = device.run(circuit, shots=shots) + return task + def get_quantum_counting_results( task, diff --git a/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py b/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py index 5136ca41..784b6131 100644 --- a/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py +++ b/test/unit_tests/braket/experimental/algorithms/quantum_counting/test_quantum_counting.py @@ -11,17 +11,15 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. -import numpy as np from unittest.mock import MagicMock + +import numpy as np + from braket.circuits import Circuit from braket.devices import LocalSimulator - from braket.experimental.algorithms.quantum_counting import quantum_counting as qc - -# ============================================================ # Oracle / circuit construction tests -# ============================================================ def test_oracle_circuit_single_marked(): @@ -59,9 +57,7 @@ def test_grover_circuit_unitarity(): np.testing.assert_array_almost_equal(product, np.eye(len(u)), decimal=10) -# ============================================================ # Circuit construction tests -# ============================================================ def test_quantum_counting_circuit_construction(): @@ -86,9 +82,7 @@ def test_inverse_qft_for_counting_2_qubits(): assert len(qft_circ.instructions) == 4 -# ============================================================ # End-to-end counting tests -# ============================================================ def _expected_M(n_counting: int, M_true: int, N: int) -> float: @@ -261,17 +255,6 @@ def test_count_with_marked_initial_state(): N = 2 ** len(search_qubits) M_exp = _expected_M(len(counting_qubits), len(marked_states), N) - # Build the Grover circuit and extract its unitary - grover_circ = qc.build_grover_circuit(len(search_qubits), marked_states) - grover_unitary = grover_circ.to_unitary() - - # Determine ancilla qubits from circuit decomposition - n_ancilla = grover_circ.qubit_count - len(search_qubits) - ancilla_qubits = [ - max(counting_qubits + search_qubits) + 1 + i for i in range(n_ancilla) - ] - all_grover_qubits = list(search_qubits) + ancilla_qubits - # Build custom QPE circuit with marked-state initialization circ = Circuit() @@ -281,11 +264,12 @@ def test_count_with_marked_initial_state(): # Prepare |β⟩ = |11⟩ (marked state) instead of uniform superposition circ.x(search_qubits) - # Controlled-G^(2^k) for QPE + # Controlled-G^(2^k) using gate-level circuit for ii, qubit in enumerate(reversed(counting_qubits)): power = 2 ** ii - g_power = np.linalg.matrix_power(grover_unitary, power) - circ.add_circuit(qc.controlled_grover(qubit, all_grover_qubits, g_power)) + circ.add_circuit( + qc.controlled_grover_circuit(qubit, search_qubits, marked_states, power) + ) # Inverse QFT on counting qubits circ.add_circuit(qc.inverse_qft_for_counting(counting_qubits)) @@ -355,3 +339,42 @@ def test_get_quantum_counting_results_empty_counts(): assert count_estimates["phases"] == [] assert count_estimates["estimated_counts"] == [] assert count_estimates["best_estimate"] is None + + +def test_run_quantum_counting(): + """run_quantum_counting should run the circuit and return a task.""" + counting_qubits = [0, 1, 2] + search_qubits = [3] + marked_states = [0] + + circ = Circuit() + circ = qc.quantum_counting_circuit(circ, counting_qubits, search_qubits, marked_states) + + device = LocalSimulator() + task = qc.run_quantum_counting(circ, device, shots=100) + + count_estimates = qc.get_quantum_counting_results(task, counting_qubits, search_qubits) + + assert count_estimates["best_estimate"] is not None + assert count_estimates["search_space_size"] == 2 + + +def test_controlled_grover_circuit_construction(): + """Controlled Grover circuit should produce a non-empty circuit.""" + control = 0 + search_qubits = [1, 2] + marked_states = [1] + + circ = qc.controlled_grover_circuit(control, search_qubits, marked_states) + assert len(circ.instructions) > 0 + + +def test_controlled_grover_circuit_power(): + """Controlled Grover circuit with power > 1 should have more gates.""" + control = 0 + search_qubits = [1, 2] + marked_states = [1] + + circ_p1 = qc.controlled_grover_circuit(control, search_qubits, marked_states, power=1) + circ_p2 = qc.controlled_grover_circuit(control, search_qubits, marked_states, power=2) + assert len(circ_p2.instructions) > len(circ_p1.instructions) From 2b6d28f72ab6ab1b1fbc4e39709ff56c9658cdfc Mon Sep 17 00:00:00 2001 From: axif Date: Fri, 27 Feb 2026 23:08:23 +0600 Subject: [PATCH 8/8] fix: Apply Z gate in the controlled diffusion operator to correct the inherent -1 global phase, removing the need for post-processing phase adjustments. --- .../quantum_counting/quantum_counting.py | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py b/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py index c9bc4049..68aadb0f 100644 --- a/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py +++ b/src/braket/experimental/algorithms/quantum_counting/quantum_counting.py @@ -173,6 +173,10 @@ def _controlled_diffusion_circuit( for sq in search_qubits: _add_controlled_h(circ, control, sq) + # Apply Z gate to correct the -1 global phase difference between + # I - 2|s>: {count} counts -> phase = {ph:.4f}, M ~ {m_est:.4f}") if len(sorted_cr) > 6: @@ -484,8 +475,7 @@ def _get_counting_estimates( for bitstring in counting_register_results: y = int(bitstring, 2) raw_phase = y / (2**n_counting) - # Correct for -1 global phase from MCZ decomposition - phase = abs(raw_phase - 0.5) + phase = raw_phase M_est = N * (np.sin(np.pi * phase) ** 2) phases.append(phase) estimated_counts.append(M_est)