From fa2cdd3ebcad0467e7fec9319d1061099826e347 Mon Sep 17 00:00:00 2001 From: Nicolas Renaud Date: Wed, 14 Feb 2024 16:37:49 +0100 Subject: [PATCH 1/3] refactor library --- example/pennylane/reupload.ipynb | 106 --- example/pennylane/train_features.npy | Bin 5128 -> 0 bytes example/pennylane/train_labels.npy | Bin 2128 -> 0 bytes example/pennylane/valid_features.npy | Bin 5128 -> 0 bytes example/pennylane/valid_labels.npy | Bin 2128 -> 0 bytes example/qiskit/vqees/vqap.ipynb | 147 ---- example/qiskit/vqees/vqees.ipynb | 230 ------ example/{dwave => }/qubols/qubols.ipynb | 4 +- example/{qiskit => }/vqls/vqls.ipynb | 0 example/{qiskit => }/vqls/vqls.py | 0 example/{qiskit => }/vqls/vqls_poisson.ipynb | 2 +- example/{qiskit => }/vqls/vqls_runtime.py | 29 +- qalcore/dwave/__init__.py | 0 qalcore/dwave/qubols/__init__.py | 0 qalcore/dwave/qubols/embedded_qubols.py | 110 --- qalcore/dwave/qubols/encodings.py | 163 ---- qalcore/dwave/qubols/qubols.py | 145 ---- qalcore/dwave/qubols/solution_vector.py | 58 -- qalcore/pennylane/__init__.py | 0 qalcore/pennylane/data.py | 82 -- qalcore/pennylane/reupload.py | 243 ------ qalcore/qiskit/__init__.py | 0 qalcore/qiskit/vqfd/__init__.py | 0 qalcore/qiskit/vqfd/numpy_fd_solver.py | 13 - qalcore/qiskit/vqfd/utils.py | 55 -- qalcore/qiskit/vqfd/variational_fd_solver.py | 103 --- qalcore/qiskit/vqfd/vqap.py | 758 ------------------- qalcore/qiskit/vqfd/vqees.py | 67 -- qalcore/qiskit/vqls/__init__.py | 31 - qalcore/qubols/__init__.py | 25 + qalcore/vqls_prototype/__init__.py | 15 + setup.cfg | 12 +- tests/qiskit/vqls/test_vqls.py | 2 +- 33 files changed, 59 insertions(+), 2341 deletions(-) delete mode 100644 example/pennylane/reupload.ipynb delete mode 100644 example/pennylane/train_features.npy delete mode 100644 example/pennylane/train_labels.npy delete mode 100644 example/pennylane/valid_features.npy delete mode 100644 example/pennylane/valid_labels.npy delete mode 100644 example/qiskit/vqees/vqap.ipynb delete mode 100644 example/qiskit/vqees/vqees.ipynb rename example/{dwave => }/qubols/qubols.ipynb (99%) rename example/{qiskit => }/vqls/vqls.ipynb (100%) rename example/{qiskit => }/vqls/vqls.py (100%) rename example/{qiskit => }/vqls/vqls_poisson.ipynb (99%) rename example/{qiskit => }/vqls/vqls_runtime.py (69%) delete mode 100644 qalcore/dwave/__init__.py delete mode 100644 qalcore/dwave/qubols/__init__.py delete mode 100644 qalcore/dwave/qubols/embedded_qubols.py delete mode 100644 qalcore/dwave/qubols/encodings.py delete mode 100644 qalcore/dwave/qubols/qubols.py delete mode 100644 qalcore/dwave/qubols/solution_vector.py delete mode 100644 qalcore/pennylane/__init__.py delete mode 100644 qalcore/pennylane/data.py delete mode 100644 qalcore/pennylane/reupload.py delete mode 100644 qalcore/qiskit/__init__.py delete mode 100644 qalcore/qiskit/vqfd/__init__.py delete mode 100644 qalcore/qiskit/vqfd/numpy_fd_solver.py delete mode 100644 qalcore/qiskit/vqfd/utils.py delete mode 100644 qalcore/qiskit/vqfd/variational_fd_solver.py delete mode 100644 qalcore/qiskit/vqfd/vqap.py delete mode 100644 qalcore/qiskit/vqfd/vqees.py delete mode 100644 qalcore/qiskit/vqls/__init__.py create mode 100644 qalcore/qubols/__init__.py create mode 100644 qalcore/vqls_prototype/__init__.py diff --git a/example/pennylane/reupload.ipynb b/example/pennylane/reupload.ipynb deleted file mode 100644 index e740388..0000000 --- a/example/pennylane/reupload.ipynb +++ /dev/null @@ -1,106 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from qalcore.pennylane.reupload import ReuploadClassifier, reupload_circuit\n", - "from qalcore.pennylane.data import read_dataset" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Load the data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "features = 'train_features.npy'\n", - "labels = 'train_labels.npy'\n", - "train_dataset = read_dataset(features,labels)\n", - "\n", - "features = 'valid_features.npy'\n", - "labels = 'valid_labels.npy'\n", - "valid_dataset = read_dataset(features,labels)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Define the solver" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "solver = ReuploadClassifier(reupload_circuit, train_dataset, valid_dataset, num_layers=2)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Process the data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "solver.process_data(npts=100, features=[0,1,2], normalization=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Solve the system" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "solver.train(epochs=5)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "mediq", - "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.8.0" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/example/pennylane/train_features.npy b/example/pennylane/train_features.npy deleted file mode 100644 index 6fcc1fda7786bb98032cee3182d4bc6a4ac1bea9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5128 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 diff --git a/example/pennylane/train_labels.npy b/example/pennylane/train_labels.npy deleted file mode 100644 index 782a23930e00ac0ece16682f9ce57233537f1d18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2128 zcmbR27wQ`j$;eQ~P_3SlTAW;@Zl$1ZlWC!@qoAIaUsO_*m=~X4l#&V(cT3DEP6dh= zXCxM+0{I$7rUp8iItsN4WCJb+C}4y!M)}|n7!4291Th*Oqv3%Z0;A~xIW!m;M#Ez? LJdi_Rpwa^XQUn|V diff --git a/example/pennylane/valid_features.npy b/example/pennylane/valid_features.npy deleted file mode 100644 index 9db240747053cb05c71ac4999cd59017d40f4313..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5128 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 ZE}5?qDRpQHwR92*6Ef-V4&wiK{68zEQIG%t diff --git a/example/pennylane/valid_labels.npy b/example/pennylane/valid_labels.npy deleted file mode 100644 index 782a23930e00ac0ece16682f9ce57233537f1d18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2128 zcmbR27wQ`j$;eQ~P_3SlTAW;@Zl$1ZlWC!@qoAIaUsO_*m=~X4l#&V(cT3DEP6dh= zXCxM+0{I$7rUp8iItsN4WCJb+C}4y!M)}|n7!4291Th*Oqv3%Z0;A~xIW!m;M#Ez? LJdi_Rpwa^XQUn|V diff --git a/example/qiskit/vqees/vqap.ipynb b/example/qiskit/vqees/vqap.ipynb deleted file mode 100644 index 4e6f485..0000000 --- a/example/qiskit/vqees/vqap.ipynb +++ /dev/null @@ -1,147 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "from qalcore.qiskit.vqfd.vqap import VQAP\n", - "from qiskit.circuit.library.n_local.real_amplitudes import RealAmplitudes\n", - "from qiskit.algorithms.optimizers import COBYLA\n", - "from qiskit.quantum_info import Statevector\n", - "from qiskit import Aer\n", - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "nqbits = 3\n", - "source = np.ones(2**nqbits)" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "# compute the VQLS solution\n", - "ansatz = RealAmplitudes(nqbits, entanglement=\"full\", reps=3, insert_barriers=False)\n", - "vqap = VQAP(\n", - " ansatz=ansatz,\n", - " boundary='Dirichlet',\n", - " optimizer=COBYLA(maxiter=200, disp=True),\n", - " quantum_instance=Aer.get_backend(\"aer_simulator_statevector\"),\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - " Return from subroutine COBYLA because the MAXFUN limit has been reached.\n", - "\n", - " NFVALS = 200 F =-3.494632E+00 MAXCV = 0.000000E+00\n", - " X = 1.085281E+00 3.207679E-01 1.359378E+00 1.654414E+00 2.659440E+00\n", - " -3.413748E+00 9.637551E-02 1.790847E+00 6.980944E-02 -2.929797E-01\n", - " 2.035284E+00 3.204207E+00\n" - ] - } - ], - "source": [ - "# solve with vqap\n", - "res = vqap.solve(source)\n", - "vqap_solution = np.real(Statevector(res.state).data)\n", - "vqap_solution = np.insert(vqap_solution, [0,2**nqbits], [0,0])" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "#construct the matrix\n", - "from qiskit.quantum_info.operators import Operator\n", - "from qiskit.algorithms.linear_solvers.matrices import TridiagonalToeplitz\n", - "import numpy as np \n", - "from qiskit.algorithms.linear_solvers.numpy_linear_solver import NumPyLinearSolver\n", - "\n", - "matrix = TridiagonalToeplitz(nqbits, 2, -1).matrix\n", - "classical_solution = NumPyLinearSolver().solve(matrix, source / np.linalg.norm(source))\n", - "ref_sol = classical_solution.state / np.linalg.norm(classical_solution.state)\n", - "ref_sol = np.insert(ref_sol, [0,2**nqbits], [0,0])\n" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAGdCAYAAADAAnMpAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy89olMNAAAACXBIWXMAAA9hAAAPYQGoP6dpAABcKUlEQVR4nO3dd3hUZd7G8e/MpEMSSiC00EJvCV06QgAbioqiq6LYOy7bZItueV3UVdddRVlZwa7o2gAVRZQepJnQe0kgnUB6nZn3j5MCCkog5JnJ3J/ryrWTMyfhZkG4+Z3nPMfmdrvdiIiIiBhiNx1AREREfJvKiIiIiBilMiIiIiJGqYyIiIiIUSojIiIiYpTKiIiIiBilMiIiIiJGqYyIiIiIUX6mA5wNl8tFSkoKoaGh2Gw203FERETkLLjdbvLy8mjVqhV2+5nnH15RRlJSUoiKijIdQ0RERM5BcnIybdq0OeP7XlFGQkNDAesnExYWZjiNiIiInI3c3FyioqKq/h4/E68oI5WXZsLCwlRGREREvMzPLbHQAlYRERExSmVEREREjFIZEREREaNURkRERMQolRERERExSmVEREREjFIZEREREaNURkRERMQolRERERExSmVEREREjFIZEREREaNURkRERMQor3hQnogYUJAFG/4LRSdMJzl/Nht0HgfRY0wnEZHTUBkRkR/b8SksngGFWaaT1J51L0HszTDhCQhuZDqNiJxEZUREqhUcg89/Dds/sj5v3gO6Xmo2U23IS4OEdyDhLdj/DVz5AnSOM51KRCqojIiIZediWPwIFGSCzQHDfwmjfgt+gaaT1Y5+U+GT+yD7ALx9rfX5+CcgKMx0MhGfpwWsIr6uMBs+vAsW3GQVkWbd4M6vYeyf6k8RAWh7Edy7Bi66H7DB5jfgpSHWpEREjFIZEfFluz6Hly6Cre+DzW5NQ+5eAa37mU52YQSEwCWz4LbPoHF7yD0Cb14Nix6BkjzT6UR8lsqIiC8qOg4f3wvv3Qj56RDRBe5YCnF/Bv8g0+kuvPbD4L61MOge6/NN8+GloXBgudFYIr5KZUTE1+z5yro8kfguYIOhD8M9q6DNANPJ6lZAA7jsabh1MTRqCzlJ8MZV8NmvoCTfdDoRn6IyIuIrik7AJw/AO9dBXio07QS3fwnj/+Yb05Az6TAC7ouHAXdYn2/4L7w8FA6tNptLxIeojIj4gr1fW9OQhLcAGwx5EO5dDW0Hm07mGQIbwhXPwdRPITwKThyG1y6Hz38LpQWm04nUeyojIvVZcS4sfMi6lTUvBZp0hGlfWBt/+QebTud5Oo621pL0v836fP1/4OVhcHityVQi9Z7N7Xa7TYf4Obm5uYSHh5OTk0NYmPYEEDkr+7+BTx+y7hgBGHwfjH3MuqOkFrjdblxucLrcuNyVH9bnbre74jhV71nHT3++y+3G5bLOdborv77iayu+j7Pya1w/+HEqvo/L9YMf56TzAQa0b0L3ljX482PfMlj4cMX/fza46D4Y86da+/9PxBec7d/fKiMi9U1JHnz1J+sOEbBuYb1qNrQfftbfIjm7kLe+O8yihBRyi8tP+5e85//J8WPjekQyfWxnerUOP7svKM6BL/8A379pfd4kGia9rMtbImdJZUTEFx1Ybk1DcpKszwfdbd2uG9DgZ7/U5XKzYm8mb8Yf5tvdGbVWNhx2G3Yb2G027DYbDrsNm63yeOXHSZ/brXMdttOcZ6fiuK1G3ze/pJzV+7Kqfk5x3a1S0rvNWZaSvUutKUleCtaamwdgzB91qUvkZ6iMiPiSknz4+nHrThCwblW9ajZ0GPmzX3qisJT3Nybz1rokkrILq46P6BzBzRe1o2tk6KklofIv/aqC8IMycVIJsNlsF+pnXGP7MvJ58Zu9LExMoeLKDWO7NWd6XGf6tGn089+g6AR8+XtIeNv6vGlna0oSNfBCRRbxeiojIr7i0Gr45H7rDhCAAbfDuL9CYOhPftmWIyd4I/4wixJTKCl3ARAa5Md1/aO4+aK2dGzW8EInN2J/Zj4vfrOPTxOOVpWSi7s2Y3pcF2KjGv38N9jzpTUlyU+zdq0d+hCM/r1v3x4tcgYqIyL1XWkBfP0X644PsG5JvfIFiL74jF9SXOZk8ZZU3lx3mMTkE1XHe7QMY+qQdlwZ24qQAN94fuaBzHxe/HYfn3xfXUpGdWnG9LjO9Gvb+Ke/uOg4fPEobHnP+jyiK1z9MrTuf2FDi3gZlRGR+uzwWmsacvyg9Xn/22Dc3874BNrk7ELeWneY9zcmc7ywDIAAh53LerfgliHt6de2kUddUqlLh7IKePHbfXz8/VGcFa1kZJdmTB/bmf7tfqaU7PocFk2HggxrSjLsERj9aP16wKDIeVAZEamPSgvhm7/BupcBN4S1hiv/DZ3ifnSqy+VmxZ5M3og/xPI9mVWLN1s3CuYXg9syZWAUEQ31l2alw8cKmP3tPj7cXF1KRnSOYPrYzgxo3+TMX1iYDV/8FrZ+YH3erDtMeqn+PmxQpAZURkTqm6Tv4JP7IHu/9Xnfm2HC3yHo1DtCjhdYC1Lf/u7HC1KnDmnPmG7Ncdh9cwpyNpKOFVaUkiOUV5SSYZ2aMn1sFwZ1+IlSsnMRLP4lFGSCzQEjZsDI34JfQB0lF/E8KiMi9UVZEXzzfxA/G3BDaEtrbUjncaeclph8gjfXnbogNSzIj+sGRHHzRe3oEPHzt/dKteTsQl5avo8PNlaXkiEdmzI9rjMXdWx6+i8qOAaf/xq2f2R9HtnLmpK0jKmj1CKeRWVEpD5I3mBNQ47ttT6PvcmahgQ3AqwFqYsSU3hr3WESj+RUfVnPVhULUmNaExzgMBC8/jhyvJCXlu/ng43JlDmtPy4v6tiE6WO7MCT6DKVk+yfw2QwoPAZ2PxjxaxjxK01JxOeojIh4s7JiWP53WPsCuF3QsAVM/Bd0vQSwLiW8/d1hFmxM5sRJC1Iv79OSW4a0o2+U7y5IvVCOniji5eX7WLChupQM6tCER8Z2Zkh00x///52faRWSnQutz1v0tvYladG7jpOLmKMyIuKtjm6Cj++DrN3W532mwCVP4gxqzMozLEi96aK2XD9AC1LrQsqJIl5evp8FG5IpdVqXwwa2b8wjcV0Y+sNS4nZbl2w++zUUZVtTklG/g+G/BIe/oZ+BSN1RGRHxNuUlsPxJWPO8NQ1p0BwmPs/xqHHWDqnfHSY5u6jq9JFdmjH1onZcrAWpRqTmFDFn+X7e3ZBMacUanQHtGjM9rjPDO0WcWkryM6zFrbsWW5+3jIFJcyCyh4HkInVHZUTEm6R8b+0bkrHD+rzXZLbF/JH53+eyaEtK1V92YUF+XF+xILW9FqR6hLScYuas2M8765Oqfp36tW3E9LgujOx8Uilxu2Hr/6wFrsUnwO5v7Uky7BFw+MZGc+J7VEZEvEF5Kax8GlY9B24n7pAI4rv/gScPd2HLSQtSe7UOY+pF7ZkY00oLUj1Uem5FKfkuqepuptioRjwS15lRXZpVl5K8NFj0COz5wvq8VV9rStK8m5ngIheQyoiIp0tNtKYh6dsA2NFkLA8cv5GDRSGAtSD1ij4tuVkLUr1KRm4x/1l5gLe/O0xxmVVKYqIa8cjYzozuWlFK3G7YssDaLK04BxwBcPHvYchDmpJIvaIyIuKpnGWw6lncK/+BzVVOrj2cmSW38pnzIsBakHrzRe24fkAbmmpBqtfKyCtm7soDvLmuupT0aRPO9LGdGdOtuVVKclNh0cOw9yvri1oPsO64adbFYHKR2qMyIuKJ0rZS/tG9+GVY05DPnYP4U9k0jhHOqC7NmDqkHaO7akFqfZKZV8LcVQd4M/4wRWVOAHq3DufhsZ2J694cG0DCO7DkUSjJBUcgjPkjDHkA7LokJ95NZUTEkzjLSP3s7zTb/G/8KOe4uyGPld3GyoCRXD8wipsGa0FqfZeVX11KCkutUtKzVRjTx3ZmXI9IbLkp1pRk39fWF7QZZE1JIjoZTC1yflRGRDxAcZmT5atW0GnNr+nktJ4p85WzP29EPMKVQ/tqQaoPyi4oZe6qA7yx9hAFFaWkR8swHh7bmfHdm2NPfAuW/B5K88AvCMY+BoPv1ZREvJLKiIhBh48V8Hb8fhpsfJn73AsIsDk54W7A4ja/pOf4O4ht21gLUn1cdkEpr64+wGtrqktJtxahTB/bmQltyrAveggOLLdObjsErpoNTaPNBRY5ByojIoa8810Sr336BU/7zSHWfgCAQ01HEn79bBpHtjWcTjzN8YJSXl19kNfWHiK/pBywSslDF3fi0tIvsS/9I5Tmg18wxP0ZBt0NdrvZ0CJnSWVExIAl21JZ8O6rzPH7J4G2csr8Q3Fc9jT22BtBkxD5CScKS5m3+iDz1xwir6KUdIlsyO8uCmHM7r9iO7TSOrHrZTDlLV22Ea9wtn9/n1O9nj17Nu3btycoKIjBgwezfv36s/q69957D5vNxqRJk87lhxXxaOsOHOPJ95byT7+XCLSV444ei/9D67H3/YWKiPysRiEBzBjfldW/G8P0sZ0JDfJjT3o+d3yawYRjM9gS8yfcfkGw+3NrkzyReqTGZWTBggXMmDGDxx9/nM2bNxMTE8OECRPIyMj4ya87dOgQv/71rxkxYsQ5hxXxVLvScrnvjXU8Z/8XjWwFuFv1w3bjexDWynQ08TLhIf78clwXVv9uDI/EdSYsyI89mYVc+V13nva7xzpp+d/h0GqzQUVqUY3LyHPPPcddd93FtGnT6NGjB3PmzCEkJIR58+ad8WucTic33XQTf/nLX+jYseN5BRbxNEeOF3LrvPXcU/4O/ez7cAeGYbtuPvgFmI4mXiw82J9H4rqw+tExzBjXhfBgf14+MZgPnSOtByl+eCcUZJmOKVIralRGSktL2bRpE3FxcdXfwG4nLi6O+Pj4M37dX//6V5o3b84dd9xxVj9OSUkJubm5p3yIeKLjBaVMnbeeHvnruNfPeiKr7arZ0Li92WBSb4QF+fPw2M6s/t3FTIxpxR/LbmO/uzXkpcJHd4PLZTqiyHmrURnJysrC6XQSGRl5yvHIyEjS0tJO+zWrV6/m1VdfZe7cuWf948yaNYvw8PCqj6ioqJrEFKkThaXl3P76Bgozk/hnwBzr4KC7oceVZoNJvRQa5M+z18XQr1Nr7it9mGICYP8yWPsv09FEztsFvT8sLy+PW265hblz5xIREXHWXzdz5kxycnKqPpKTky9gSpGaK3e6ePCd79mSdIyXgmbTiDxoGQPj/890NKnHAvzsvHxzf+yRPXis7FYA3Mv+BknrDCcTOT81ejxkREQEDoeD9PT0U46np6fTokWLH52/f/9+Dh06xMSJE6uOuSpGin5+fuzevZvo6B9v4hMYGEhgoB4QJp7J7Xbz+4+38s2uDB4N+JB+7IKAUJg8H/z0+1YurLAgf+ZPG8jVL5bycfEOrnaswf3BNGz3rYGQJqbjiZyTGk1GAgIC6N+/P8uWLas65nK5WLZsGUOGDPnR+d26dWPr1q0kJCRUfVx55ZVcfPHFJCQk6PKLeKVnvtrN+xuPMNK+hXvsn1oHr/y3dseUOtMyPJj5tw/iSfvd7He1xJaXgvvje8Hzt40SOa0aX6aZMWMGc+fO5fXXX2fnzp3cd999FBQUMG3aNACmTp3KzJkzAQgKCqJXr16nfDRq1IjQ0FB69epFQIDuNhDv8tqag8z+dj/NOc4rDV/Bhhv6T4Ne15iOJj6me8swnrtlONOd0ylx+2Pb+yXEv2g6lsg5qdFlGoApU6aQmZnJY489RlpaGrGxsSxZsqRqUWtSUhJ2bVUs9dBnW1L5y+Id2HHxUeQ8gnKyIbIXXDLLdDTxUcM6RXD7tRP564d7eMJ/Hq6lf8YedRFEDTQdTaRGtB28yFlYuz+L2+ZtoNTpYn67pVycPh/8G8A9KyCis+l44uNeXLaH9ssf4grHOopCWhP80BoIbmw6lsiF3Q5exJfsSMnlnjc2Uep08UjHFEanv2a9MfF5FRHxCA+M6czGPn/mkCuS4MKjnHj3Lq0fEa+iMiLyE5KzC7l1/nrySsoZ39bG9JynrXUifW+BPtebjicCgM1m44/XDOa1Vo9T4vajUdJSjn3zb9OxRM6ayojIGRzLL2HqvPVk5pXQIzKE2cFzsBVkQPMecOnTpuOJnMLPYec306Ywv8GdAISt+isn9n1nOJXI2VEZETkNa3fVjRzMKqB1o2De7xmP/+EV4B8C170GASGmI4r8SINAP665988st1+EP+UUvTOVotzjpmOJ/CyVEZEfKHO6uP/tzSQmn6BxiD8LJjhpGP8P683Ln4VmXc0GFPkJzcOCaTttHkdpRktXGtv/MxWnU8+vEc+mMiJyErfbze8+3MLy3ZkE+dt5fUpH2nzzkPWU1JgbIfYXpiOK/KyOUa3JufwVSt0OBhSs5PP5/4cX3DgpPkxlROQkTy3ZzUebj+Kw23jpF7H0Wf9b6+moEV3gsmdMxxM5az0GjmFfzG8AGJ/8Lz787HPDiUTOTGVEpMK81QeZs2I/AE9e05sxWe9aT0X1C7LWiQQ2NBtQpIZ6XP0ohyNGEWgrp//6X/L5xj2mI4mclsqICLAwMYW/Lt4BwG8mdOW65kfhm4on8F76NET2NJhO5BzZbLS7/TVOBETSwZ6Oa+F01u3PMp1K5EdURsTnrd6bxa/eTwDgtqHtuX9QY/jf7eB2Qu/roN9UswFFzkdIE0JvehMnDq6wr+XLN59ib3qe6VQip1AZEZ+27WgO97y5kTKnm8v7tOSxy7tj+/R+yD0KTTvBFf8Em810TJHz4mg3GNeYPwHwO/d8/vbqB6TnFhtOJVJNZUR8VtKxQm6bv4GCUidDOjbluetjsH83G/YsAUdgxTqRUNMxRWqF//DplHUYS5CtjMeLn+a+eSvJLyk3HUsEUBkRH5WVX8LUed+RlV9C95Zh/GdqfwJTN8PXf7ZOuGQWtOhtNKNIrbLb8Z88l/IGLYm2p3LTsX9x35sbKdMeJOIBVEbE5+SXlDNt/gYOHSukTeNgXp82kDB3vrVOxFUOPSbBgNtNxxSpfQ2a4nf9PNw2B9c6VtPi4If8/qOt2oNEjFMZEZ9SWu7ivrc2sfVoDk0aBPDG7YNoHhoInzwAOUnQuD1c+W+tE5H6q91QbBf/HoC/+r1GwuZ1/GvZXsOhxNepjIjPcLnc/PZ/iazam0Wwv4N5tw2kY7OG8N1/YPdn4Aiw1okEhZuOKnJhDZ8B0WMItpUy2/9fzPl6G+9vTDadSnyYyoj4jFlf7OSThBT87DZevrkfsVGN4Ohm+OqP1gnj/w9a9TWaUaRO2O1w9SvQsAVd7Ef5i9/rzPxoKyv2ZJpOJj5KZUR8wtyVB5i76iAAT0/uw+iuzaE4B/43DVxl0H0iDLrbcEqROtSwGVz7X9w2O1P8ljORVdz/1ia2Hc0xnUx8kMqI1HuffH+UJz7fCcCjl3bjmn5twO2GhQ/B8UPQqC1c+aLWiYjv6TAC26jfAfBk4DxalCVx+2sbOHqiyHAw8TUqI1KvrdyTya8/SATg9mEduGdkR+uNDf+FHZ+C3R8mvwbBjYxlFDFq5G+gw0iC3MXMDZ5NTl4et81bT05hmelk4kNURqTe2nLkBPe+tYlyl5srY1rxx8u7Y7PZIDURvrTuJmDcX6BNf7NBRUyyO+Ca/0KDZnR0HeLJkLfZm5HP3W9upKTcaTqd+AiVEamXDmUVMG3+BgpLnQzvFMEz18Vgt9ugOBc+uA2cpdDlUrjoftNRRcwLjYRr5gI2rnYt5brA7/juYDa//mALLpf2IJELT2VE6p2MvGKmzlvPsYJSerYK4+Wb+xHgZ7fWiSx+BLIPQFgbmPSS1omIVIq+GEb+GoAn/f9LtD2NRYkpPPXlLsPBxBeojEi9kldcxrT5G0jKLqRtkxBemzaI0CB/683Nr8O2D8HmgMnzIKSJ2bAinmbUo9BuGI7yAj6MeIVASvnPigO8EX/IdDKp51RGpN4oKXdy71ub2J6SS0RDa3fVZqGB1ptp2+AL664Bxj4GbQebCyriqRx+cO1/IaQpjXJ38UGHzwD488LtfLU9zXA4qc9URqRecLnc/PqDLazZd4yQAAfzbxtE+4gG1psl+dY6kfJi6DQOhj5sNKuIRwtrZW2IBvRJ/YAnuuzD5YaH3/ue75OOGw4n9ZXKiHg9t9vN/322k0WJ1u6qc27uT+824ZVvwme/gmN7IbQVXP0fa/dJETmzznEw7BEAfpH+D67vWE5xmYs7Xt/IoawCs9mkXtKfyuL1/rPyAPPWWLurPnNdDCO7NKt+M+Ft2PJexTqRV6FBU0MpRbzMmD9C1GBsJXnMcj1H31YhZBeUctv89RzLLzGdTuoZlRHxah9uOsKTX1ir/f94eXcm9W1d/WbGTvjMujuAi38P7YYaSCjipRz+1kLv4MY40hJ4u/1ntGkczKFjhdz5xkaKSrUHidQelRHxWt/uzuC3H24B4K4RHbhzRMfqN0sLKtaJFEHHi62nlIpIzYS3gUlzAAjZPJcPRmUTHuzP90knePi973FqDxKpJSoj4pUSkk9w/1ubcbrcTIptxcxLu596whe/hcxd0DASrnlF60REzlXXS2DIgwC0XD6DN65tQYCfnaU70vnrou243Sokcv70J7R4nQOZ+dz+2gaKypyM6BzB05MrdletlLgAvn8LbHbrNsWGzc2FFakP4v4MrQdAcQ4x62bw/OSe2Gzwevxh5q46YDqd1AMqI+JVMnKt3VWzC0rp0yacOTf3t3ZXrZS5Bxb/0no96nfQYaSZoCL1SeX6kaBwOLKByzJe4Q+XWdPIv3++i4WJKYYDirdTGRGvkVtcxq3zN3DkeBHtm4Yw77aBNAj0qz6hrMhaJ1JWYJWQkb8xllWk3mncDq56yXq99gXujNzLtGHtAfj1+4msO3DMXDbxeioj4hVKyp3c/cZGdqbmEtEwkDduH0xEw8BTT1ryKGRshwbNrKeQ2h1mworUV92vgMH3Wq8/voc/Dg/jkp4tKHW6uPuNjexNzzObT7yWyoh4PKfLzYwFiaw7kE3DQD9emzaQtk1DTj1p6/9g02uAzXr6aGikiagi9d+4v0LLWCg6juOjO3n+up70b9eY3OJybpu/gYzcYtMJxQupjIhHc7vd/HXRdj7bmoq/w9pdtVfr8FNPOrYfFk23Xo/8tfX0URG5MPwC4brXIDAMktcRtPpJ5k4dQMeIBhw9UcS01zaQX1JuOqV4GZUR8WgvLd/P6/GHAXj2+liGd4449YSyYvjgVijNh3bDrKeOisiF1aQDXPmC9Xr1P2mSspLXpg0iomEA21NyeeDtzZQ5XWYzildRGRGP9f7GZP7x5W4AHruiB1fGtPrxSV/9EdK2QkhT6zZeh9+PzxGR2tdzEgy803r98d209c/h1VsHEuzvYMWeTP7w8VbtQSJnTWVEPNKynenM/GgrAPeOiub24R1+fNL2T2DDXOv11a9YTxsVkboz/glo0RsKj8GHdxLTqiEv/qIvdhu8v/EI/162z3RC8RIqI+JxNh0+zgPvWLurXtOvNb+7pOuPT8o+CAsfsl4Pe8R6yqiI1C3/ILjudQhoCIdXw4qnGNs9kr9N6gXAP7/ewwcbkw2HFG+gMiIeZV9GPne8voHiMhejuzbjqWv7YLPZTj2pvAT+Nw1KciFqsPV0URExo2k0TPyX9XrlP2D/t9w0uB33j44GYOZHW1m5J9NgQPEGKiPiMdJzi7l13npOFJYRE9WIl27qh7/jNL9Flz4OKd9DcGNrV0iHf92HFZFqvSdDv1sBN3x0N+Sl85sJXZkU24pyl5v73trE9pQc0ynFg6mMiMf46+IdHD1RRMeIBsy/bSAhAadZjLpzMXz3svV60hzrqaIiYt6lT0HznlCQAR/dic3t4unJMQzp2JSCUifT5m/g6Iki0ynFQ6mMiEfYl5HP51tTAXjxF/1o0iDgxycdPwyf3m+9HvKg9TRREfEM/sHW/iP+DeDgSlj5DAF+dubc0p+ukaFk5JUwbf56corKTCcVD6QyIh7hpeX7cLthXI9IerQK+/EJzjL43+1QnGM9PXTs43UfUkR+WrMucMVz1usVT8LBVYQH+zN/2kBahAWxJz2fe97cSEm502xO8TgqI2Jc0rFCPk2wnvr54MWdTn/Ssr/A0Y3WU0MnzwO/00xORMS8mBsg9mZwu+DDOyE/k1aNgpk/bSANA/1YdyCb33ywBZdLe5BINZURMW7Oyv04XW5GdI4gJqrRj0/Y8yWsrdjt8aqXrKeHiojnuuxpaNYN8tPg47vB5aJ7yzBevrkffnYbCxNT+MdXu02nFA+iMiJGpeYU8b+NRwB4aEznH5+QcwQ+vsd6Pfhe66mhIuLZAhpY60f8gmH/N7DmnwCM6Gzdrg/w8vL97EjJNRhSPInKiBj1ysoDlDpdDOrQhEEdmpz6prMM/ncHFB23nhI67q9GMorIOWjeHS77h/X6myfgcDwA1/Zvw8SKRzs8t3SPqXTiYVRGxJis/BLeXZ8EnGGtyLdPQPI66+mg171mPS1URLxH35uhzxRwO60F6AXHAHgkrjN2G3y9M53E5BNmM4pHUBkRY15dfZDiMhcxbcIZ8cOn8e79GlZbo12ufMF6SqiIeBebDS5/Dpp2hrwU+ORecLmIbtaQa/pZewQ9q+mIoDIihpwoLOWNtYcAeHBM51O3fM9NsRa9gfVU0J6T6jyfiNSSwIYVk80g2PsVxFuL0aeP7Yyf3cbKPZmsP5htNqMYpzIiRry29hAFpU66tQhlbLfm1W84y63bAQuPWU8DHf+EuZAiUjta9IJLnrReL/srJK8nqkkI1w+MAuCZr3bjdutWX1+mMiJ1Lr+knPlrDgHwwMWdsNtPmoqseAoOr7GeAnrd69ZTQUXE+/W/DXpeA65ya/1IYTYPjelEgJ+d9QezWbPvmOmEYpDKiNS5t9YdJqeojI4RDbisd8vqNw6utJ76CdZTQJtGmwkoIrXPZrP+u27SEXKSYeFDtAwP5qbBbQFNR3ydyojUqaJSJ/9ddQCA+y/uhKNyKuJ2w5e/B9zQb6r1FFARqV+CKu6Ms/vDrsVwcBX3jY4m2N9BQvIJvtmVYTqhGKIyInXqvQ1JZOWX0qZxMFfFtqp+Y/fnkLbVujwT9xdzAUXkwmoZY/2DA2DFUzQPDeLWoe0BeParPdom3kepjEidKSl38spKaypy76ho/B0Vv/3cblhesbht0F0Q0uQM30FE6oXhv7SmI4dWwaE13DOyIw0D/diRmsuS7Wmm04kBKiNSZz7afJTUnGIiwwKZ3L9N9Rt7lkDaFuvR40MeMhdQROpGoyjod4v1esWTNG4QwB3Drb2Enlu6B6emIz5HZUTqRLnTxUvL9wFw98hogvwd1hs/nIo0aGoooYjUqeEzrOnIwZVweC13jOhAeLA/+zLyWZh41HQ6qWMqI1InFiamkJxdRJMGAdw4KKr6jT1fQmoC+IfAUE1FRHxGoyjoe5P1evmThAX5c8+ojgA8//Veypwug+GkrqmMyAXncrmZ/a01FbljeAdCAvysN9xuWFExFRl4JzSIOMN3EJF6afgMsPvBwRWQtI7bhrYnomEAh48V8tHmI6bTSR1SGZELbsn2NPZnFhAW5MfUIe2q39i7FFK+r5iKPGwuoIiY0bgdxFZPR0IC/LhvtPXQzH8v20dJudNgOKlL51RGZs+eTfv27QkKCmLw4MGsX7/+jOd+9NFHDBgwgEaNGtGgQQNiY2N58803zzmweBe3280L31hTkduGdSA0yL/yjZOmIndAw2aGEoqIUSN+ZU1HDnwLSd9x0+C2tAgL4uiJIhZsSDadTupIjcvIggULmDFjBo8//jibN28mJiaGCRMmkJFx+s1qmjRpwh/+8Afi4+PZsmUL06ZNY9q0aXz55ZfnHV483ze7MtiZmktIgINpFXsJALBvGRzdBH7BmoqI+LLG7SDmRuv1iicJ8nfwwBhrOvLCN/soKtV0xBfUuIw899xz3HXXXUybNo0ePXowZ84cQkJCmDdv3mnPHz16NFdffTXdu3cnOjqa6dOn06dPH1avXn3e4cWznTwVueWidjRuEFD5BiyfZb0eeAc0bH6G7yAiPmHEr8DmgP3fQPIGpgyIonWjYDLzSnhr3WHT6aQO1KiMlJaWsmnTJuLi4qq/gd1OXFwc8fHxP/v1brebZcuWsXv3bkaOHHnG80pKSsjNzT3lQ7zP2v3HSEg+QaCfnTtGdKh+Y/8yOLpRUxERsTTpALHV05EAPzvT4zoD8PKK/eSXlBsMJ3WhRmUkKysLp9NJZGTkKccjIyNJSzvzrnk5OTk0bNiQgIAALr/8cl544QXGjRt3xvNnzZpFeHh41UdUVNQZzxXP9cI3ewG4cVBbmodWPH3X7YblT1mvB9wOoZFn+GoR8Skjfm1NR/Z9DUc2cU3f1nSIaEB2QSmvrTloOp1cYHVyN01oaCgJCQls2LCBJ554ghkzZrB8+fIznj9z5kxycnKqPpKTtYjJ22w8lM26A9n4O2zcPbJj9RsHvoUj68EvCIZNNxdQRDxLkw4Qc4P1esWT+DnsPFIxHfnPygPkFJYZDCcXWo3KSEREBA6Hg/T09FOOp6en06JFizP/IHY7nTp1IjY2ll/96ldMnjyZWbNmnfH8wMBAwsLCTvkQ7/Jixb4i1/ZrQ6tGwdbBk3db7T9NUxEROVXl2pG9X8GRTUzs04qukaHkFZfz39UHTKeTC6hGZSQgIID+/fuzbNmyqmMul4tly5YxZMiQs/4+LpeLkpKSmvzQ4kW2Hslh+e5M7Da4b3R09RsHlkPyd+AI1FRERH6saTT0ud56veIp7HYbvxzXBYB5qw9yLF9/b9RXNb5MM2PGDObOncvrr7/Ozp07ue+++ygoKGDatGkATJ06lZkzZ1adP2vWLJYuXcqBAwfYuXMnzz77LG+++SY333xz7f0sxKO8+K21VuSq2Na0a9rAOuh2w4rKtSLTIKyloXQi4tFG/gZsdtj7JRzdzISekfRqHUZBqZP/rNR0pL7yq+kXTJkyhczMTB577DHS0tKIjY1lyZIlVYtak5KSsNurO05BQQH3338/R44cITg4mG7duvHWW28xZcqU2vtZiMfYnZbHl9uty3j3nzwVObgSkuIrpiKPmAknIp6vaTT0vh62vAcrnsb2i/f41fiuTJu/gdfXHuLO4R1oHhZkOqXUMpvb7fb4ZzXn5uYSHh5OTk6O1o94uOnvfc+nCSlc2qsFL9/c3zrodsP8yyBpLQy6Gy77h9mQIuLZsvbB7IHgdsHdy3G3jGXynHg2HT7OrUPa8ZereplOKGfpbP/+1rNppNYczCpgUWIKAA9c3Kn6jUOrrCLiCNBURER+XkQn6DXZer3iaWw2G78ab60deXd9MkdPFBkMJxeCyojUmpeX78PlhjHdmtOrdXj1G5X7ivS7FcJbmwknIt6lcu3I7s8hNZGh0REMjW5KqdPFixV7GEn9oTIiteLoiSI+2nwU+OFUZDUcXm1NRYb/0lA6EfE6zbpAr2ut1yueBqiajry/8QiHsgpMJZMLQGVEasV/Vuyn3OVmaHRT+rdrXP1G5b4ifW/RVEREambkbwAb7FoMqVvo364Jo7s2w+ly8+9lmo7UJyojct4ycot5r+JR3w+OOXkqssZaL2L311RERGquWVfodY31umJrgF+N6wrAxwlH2ZueZyqZ1DKVETlvc1cdoLTcRf92jRnSsWn1GysqpiL9boFGer6QiJyDkb+lajqSto3ebcKZ0DMStxue/1rTkfpCZUTOS3ZBKW9/lwTAgxd3wmazWW8cjrf2FrH7w/AZBhOKiFdr3g16Xm29rpiO/HJcF2w2+GxrKttTcgyGk9qiMiLnZf6agxSWOunZKozRXZtVv1E5Fel7k6YiInJ+RlVMR3YuhLRtdGsRxsQ+rQD459I9ZrNJrVAZkXOWU1TGa2sOAfDQmJOmIknrrOfQ2P00FRGR89e8O/S4ynq90rqz5pG4ztht8PXODL5POm4wnNQGlRE5Z2/GHyKvpJzOzRsyvsdJT22uvIMm9iZo3M5MOBGpX0b9zvrfHZ9C+g46NmvItf3aAPCcpiNeT2VEzklhaTmvrj4IWPuK2O0VU5Hk9XDgW2sqMuJXBhOKSL0S2eNH05GHx3bG32Fj1d4s1h04ZjCcnC+VETkn73yXxPHCMto1DeGKPic9gbdyKhJzo6YiIlK7Kqcj2z+BjJ1ENQlhykBrTdpzX+3BCx61JmegMiI1VlxW/Sjv+0dH4+eo+G2UvAH2LwObQ1MREal9kT2h+0TAXbUr64MXdybAz876Q9ms3pdlNp+cM5URqbEPNiaTmVdCq/Agru7bpvqNyjtoYm+EJh3MhBOR+q1qOvIxZOyiRXgQt1xkTWGf0XTEa6mMSI2UOV3MWWFNRe4ZFU2AX8VvoSObYN/XFVORXxtMKCL1Wove0O0KwA0r/wHAfaOjCfZ3kJh8gmU7M8zmk3OiMiI18vH3Rzl6ooiIhoFV12qB6qlIzA2aiojIhVU5Hdn2IWTuJqJhILcNaw/As0v34HJpOuJtVEbkrDldbl76dh8Ad4/sQJC/w3rj6CbY+5XWiohI3WjZB7pezsnTkXtGdiQ00I+dqbl8sS3NbD6pMZUROWuLt6Rw6FghjUL8uWnwSXfKLLe2aKbPFGgabSaciPiW0SdNR7L20igkgDtGWFPZ55buxqnpiFdRGZGz4nK5eenb/QDcPqwDDQL9rDeOboa9X4LNDiO1VkRE6kjLGOh6GbhdVdOR24d3oFGIP/szC/g04ajhgFITKiNyVpbuTGd3eh6hgX7cOrR99RsVt9fR+3pNRUSkbo36rfW/Wz+ArH2EBflzz0jrz6Hnv95LmdNlMJzUhMqI/Cy3282L31hrRaYObUd4sL/1RkoC7PmiYiryG3MBRcQ3teoLXS45ZTpy69B2RDQMICm7kP9tOmI4oJwtlRH5WSv3ZrH1aA7B/g5uH3bSnTIVj/Om12SI6GQmnIj4tso7a7a+D8f2ExLgx/2jrT+P/r1sL8VlToPh5GypjMhPcrvdvLBsLwC/GNyWpg0DrTdSE2H355qKiIhZrftB5wkV05FnAOvPqhZhQaTmFPPe+iTDAeVsqIzIT/ruYDYbDx8nwGHn7pEdq9+oXCvS61po1sVMOBERqL6zZssCOLafIH8HD421piMvfrufolJNRzydyoj8pMq1ItcPbENkWJB1MHUL7FoM2DQVERHzWveHTuPA7YRVzwJwXf8oopoEk5VfwpvrDpnNJz9LZUTO6Puk46zel4XDbqtaoQ6ctFbkGmjW1Uw4EZGTjX7U+t/E9yD7AAF+dh4e0xmAl5fvJ7+k3GA4+TkqI3JGsyt2W726b2uimoRYB9O2nTQV+a25cCIiJ2szADrFnTIdubpvazpGNOB4YRnzVx80HFB+isqInNb2lBy+3pmBzQb3jz7NVKTn1dC8m5lwIiKnM+rk6chB/Bx2HhlnrWl7ZdUBcgrLDIaTn6IyIqdVudvqFX1a0bFZQ+tg+nbYuRCwVW82JCLiKaIGQvQYcJVXTUeu6N2SrpGh5BWXM3fVAcMB5UxURuRH9mXk8/m2VAAeuPjkqUjFHTQ9roLm3Q0kExH5GVXTkXfh+GHsdhszxlvTkXlrDnIsv8RgODkTlRH5kZeW78PthnE9IunWIsw6mL4Ddnxiva7cZEhExNO0HQwdLz5lOjK+RyS9W4dTWOpkzor9hgPK6aiMyCmSjhXyaUIKAA9efNKuqitPmopE9jCQTETkLFXeWZPwNpxIwmaz8auK6cgb8YdJzy02GE5OR2VETvHyiv04XW5GdmlGTFQj62DGLtj+ifVaUxER8XRtL4IOo06Zjozq0owB7RpTUu6qulNQPIfKiFRJzSniw4oHS/14KuKG7hMhsqeZcCIiNVE5Hfn+bTiRXDEdsfZFend9EkeOFxoMJz+kMiJVXll5gFKni0EdmjCoQxPrYMYu2PaR9VpTERHxFu2GQoeR4CqD1c8BMCS6KcM6NaXM6eaFZZqOeBKVEQEgK7+EdyseKPXQmJOnIv8A3NDtCmjR20w4EZFzUXlnzeY3Icea+s4YZ01H/rf5CAezCkwlkx9QGREAXl19kOIyFzFRjRjeKcI6mLkHtn1ovdZURES8Tfth0H6ENR1ZZU1H+rdrzJhuzXG63Pzr6z2GA0ollRHhRGEpb6w9BFhrRWw2m/VG5VSk6+XQso+xfCIi56zyH1Lfvwk5RwGYUbEr66eJKexNzzOVTE6iMiK8tvYQBaVOurUIZWy35tbBrL2w7X/W69GaioiIl+owAtoNB2cprP4nAL1ah3NJzxa43fBPTUc8gsqIj8svKWf+mkMAPDimE3b7SVMRtwu6XgYtY8wFFBE5X5X/oNr8OuRa+yj9clwXbDb4fGsa247mGAwnoDLi895ad5icojI6NmvApb1aWgez9sHWD6zXegaNiHi79iOg7dBTpiNdW4RyZUwrAP65VNMR01RGfFhRqZP/Vjw46v7RnXBUTkVWPWNNRbpcAq36GkwoIlILbLbq6cim1yHXevbW9LGdcdhtLNuVweak4wYDisqID3tvQxJZ+aW0aRzMVbHWvxA4th+2vG+91h00IlJfdBgFbYeAswTWPA9Ax2YNubZfawCe+0rTEZNURnxUSbmT/6ywpiL3jY7G31HxW2HlM+B2QucJ0LqfwYQiIrXIZqv+B9am1yAvDYCHxnTG32Fj9b4s4vcfM5fPx6mM+KiPNh8lLbeYyLBAJvdvYx3MPgBbFlivdQeNiNQ3HUdD1GAoL4bVzwMQ1SSEGwa2BeC5pbtxu93m8vkwlREfVO508dJyayvku0dGE+jnsN5Y+aw1Fek0Dlr3N5hQROQCOGU6Mr9qOvLgmE4E+tnZcOg4K/dmGQzou1RGfNDCxBSSs4to2iCAGwdFWQezD0Liu9brygdMiYjUN9FjoM1Aazqy5t8ARIYFcctF7QB49itNR0xQGfExLpe76vHZd4zoQEiAn/XGqoq1Ip3ioM0AgwlFRC4gm636H1wb50FeOgD3jo4mJMDBliM5LN2RbjCgb1IZ8TFLtqexP7OAsCC/qn8JcPwQJL5nvR6lqYiI1HPRY6H1ACgvgrXWdCSiYSDThrUH4Lmle3C5NB2pSyojPsTtdvPCN9ZU5LZhHQgN8rfeWPUsuMqt8WXUQIMJRUTqwMnTkQ2vQn4GAHeN6EhooB+70vL4fFuqwYC+R2XEh3yzK4Odqbk0CHAwbWh76+Dxw5DwjvVaUxER8RWd4qBVv1OmI41CArhzREfAmo6UO10mE/oUlREfcfJU5OYh7WjcIMB6o3Iq0vFiaDvYYEIRkTpks8HomdbrDa9CfiYAtw9vT6MQfw5kFvBpQorBgL5FZcRHrN1/jITkEwT62blzuNX8OZEECW9br3UHjYj4ms7jrEdelBVC/AsAhAb5c++oaACeX7aHMk1H6oTKiI944Zu9ANw4qC3NQgOtg6ues6YiHUZB24sMphMRMcBmq748vX4uFFh7jEwd0o6IhoEkZxfxwcYjBgP6DpURH7DxUDbrDmTj77Bx98jKqUgyfP+W9VpTERHxVV0mQMtYazqy1pqOhAT48cDF1nTkhW/2UlzmNBjQN6iM+IAXK/YVmdy/Da0aBVsHV/8TXGXQYSS0G2ownYiIQSffWbN+LhRYz6e5cVBbWoYHkZpTzLvrkwwG9A0qI/Xc1iM5LN+did1G1XVQco7A5jes17qDRkR8XZdLoGUMlBVA/IsABPk7eGhMZwBmf7ufwtJykwnrPZWReu7Fb621IlfFtqZd0wbWwcqpSPsR0H6YwXQiIh7g5GfWrH8FCrMBuG5AG9o2CSErv4Q34g8bDFj/qYzUY7vT8vhyezo2G9w/unIqcvSkqYiezCsiAkDXy6BFbyjNr5qO+DvsTB9rTUfmrNhPXnGZyYT1mspIPVb5ZN5Le7Wgc2SodXDN8+AshXbDocMIc+FERDzJyXfWfFc9HZnUtzXRzRpworCMeasPmctXz6mM1FMHswpYlGht2HP/6E7WwdwU2PSa9Xq0piIiIqfodjlE9obSPFj3EgAOu41fjusCwH9XHeBEYanJhPWWykg99fLyfbjcMKZbc3q1DrcOrn7emoq0HWqtFxERkWo2G4z6rfV63Zyq6chlvVrSrUUoeSXlzF11wGDA+ktlpB46cryQjzYfBeCBiyunIqmnTkVsNjPhREQ8WbcroHnPiunIywDY7TZmVExH5q85RFZ+icmE9dI5lZHZs2fTvn17goKCGDx4MOvXrz/juXPnzmXEiBE0btyYxo0bExcX95Pny/l7ZeUByl1uhnVqSv92ja2Da/4FzhJoO8TacVVERH7Mbq++jP3dHCg6DsC4HpH0aRNOYamTOcv3GwxYP9W4jCxYsIAZM2bw+OOPs3nzZmJiYpgwYQIZGRmnPX/58uXceOONfPvtt8THxxMVFcX48eM5evToeYeXH8vILea9DcnASVORvDTYNN96PUpTERGRn9RtIjTvASW51uUawGaz8avxXQF4c91h0nKKTSasd2pcRp577jnuuusupk2bRo8ePZgzZw4hISHMmzfvtOe//fbb3H///cTGxtKtWzf++9//4nK5WLZs2XmHlx+bu+oApeUu+rdrzJCOTa2Da/4F5cUQNRg6jjaaT0TE49ntJ60deRmKTgAwsnMEA9s3pqTcxeyKna2ldtSojJSWlrJp0ybi4uKqv4HdTlxcHPHx8Wf1PQoLCykrK6NJkyZnPKekpITc3NxTPuTnZReU8tY6a9viB8d0wmazQV46bKwoipqKiIicne5XQbPuUJJjXa7h1OnIexuSSM4uNJmwXqlRGcnKysLpdBIZGXnK8cjISNLS0s7qe/zud7+jVatWpxSaH5o1axbh4eFVH1FRUTWJ6bPmrzlIUZmTXq3DGN2lmXVw7b+tqUibQRA9xmxAERFvccp05CUozgHgoo5NGd4pgjKnu+pp6HL+6vRumieffJL33nuPjz/+mKCgoDOeN3PmTHJycqo+kpOT6zCld8opKuO1NYcAePDiiqlIfgZseNU6QXfQiIjUTI9J0KybVUS++0/V4RnjrTtrPtx8lAOZ+YbC1S81KiMRERE4HA7S09NPOZ6enk6LFi1+8mufeeYZnnzySb766iv69Onzk+cGBgYSFhZ2yof8tDfjD5FXUk7n5g0Z36Pi12LNv6C8CFoPgOixZgOKiHgbux1G/sZ6Hf9i1XSkX9vGjO3WHKfLzb+WaTpSG2pURgICAujfv/8pi08rF6MOGTLkjF/39NNP87e//Y0lS5YwYMCAc08rp1VQUs6rqw8C1loRu90G+ZknTUUe1VRERORc9LwaIrpUTEdeqTpcuSvrwsQUrR2pBTW+TDNjxgzmzp3L66+/zs6dO7nvvvsoKChg2rRpAEydOpWZM2dWnf/UU0/xpz/9iXnz5tG+fXvS0tJIS0sjP1+jrdry7vokjheW0b5pCJf3bmkdXPtvayrSqh90OvP6HBER+Ql2B4ysWDsS/yIUWzdU9GodzpCOTXG7YfGWVIMB64cal5EpU6bwzDPP8NhjjxEbG0tCQgJLliypWtSalJREamr1L8zLL79MaWkpkydPpmXLllUfzzzzTO39LHyY2+3m3fXWHTR3j4zGz2GHgizY8F/rhNEzNRURETkfva6Bpp2h+ASsr56OTIxpBVD1HDA5dza32+02HeLn5ObmEh4eTk5OjtaP/MD2lBwu//dqAvzsbPpjHKFB/rD0MWu9SKu+cNe3KiMiIudry/vw0V0Q3Bge2QqBoWQXlDLoia8pd7lZ9qtRRDdraDqlxznbv7/1bBovt7CikY/p2twqIgXHYH3FVGSU1oqIiNSKXtdC007W9vAV05EmDQIY3jkCgMWJulRzPlRGvJjL5a76D+DKWGtcSPwLUFYALWOhywRz4URE6hO7o/rOmrUvQom17nFiH+vP3oWJR/GCCw0eS2XEi32ffJyjJ4poEOBgTLfmFVORudabuoNGRKR29ZoMTaKhKBs2WH/WjusZSYCfnf2ZBexKyzMc0HupjHixhQnWJZrxPVsQ5O+wVnqX5kPLGOhyieF0IiL1jMOvejqy5t9Qkk9YkD8Xd7V2vNZC1nOnMuKlyp0uPttacYkmphUUZlev8tYzaERELoze10GTjhXTEWt9XtVdNVtSdKnmHKmMeKn4A8fIyi+lcYi/tYAqfrY1FWnRG7peZjqeiEj95PCDEb+2Xq99AUoLGNOtOSEBDpKzi0g8kmM2n5dSGfFSlZdoLu3dEv+SE9XPTdAdNCIiF1afKdC4AxRmwYZXCQnwI667tdeWLtWcG5URL1RS7mTJduspyVfGtLKKSGkeRPaGbpcbTiciUs85/GBk5XTk31BWVHWpZvGWFFwuXaqpKZURL7R8dyZ5xeW0CAtiUNtw2Py69caIGZqKiIjUhT5TIKwNFGTCrs8Y2SWC0CA/0nNL2HAo23Q6r6My4oUqNzq7ok9L7IdWQF6qtSugpiIiInXD4Q+xN1qvE98l0M/BJT2tJ6Yv2qJLNTWlMuJlCkrKWbYzHajY6CzhHeuN3teBX6DBZCIiPiamoozs/wZyU6su1Xy+NY1yp8tgMO+jMuJllu5Ip7jMRfumIfRuCuxabL1R+R+FiIjUjabREHURuF2wZQFDo5vSpEEA2QWlrN1/zHQ6r6Iy4mUqV2pfGdMK245PobwYmnW3HoonIiJ1K/YX1v8mvouf3calvSou1eiumhpRGfEiJwpLWbk3E6jYZKfyEk3sjVq4KiJiQs9J4BcEmbsgZXPVpZol29MoKXeazeZFVEa8yBfb0ihzuunWIpTOfhmQvA5sdmtVt4iI1L2gcOg+0Xqd8C4D2zchMiyQvOJyVu7JMpvNi6iMeJHKjc6ujG0Fie9aB6PHQmgLg6lERHxc5Zq9rR/gcJVyee+K7eF1qeasqYx4ifTcYtYdtBZETezdAhLfs96I1cJVERGjOo6G0FZQfAL2LGFiTEvAuuGgsLTcaDRvoTLiJRZvScXthn5tGxGVswlykiEwHLpqbxEREaPsDoipuFye8A6xUY1o0ziYojIn3+zKMJvNS6iMeImFJ91FU3WJptc14B9kMJWIiAAQU3FXzd6l2Aoyq5/kq0s1Z0VlxAscPlZAYvIJ7Da4vFsY7FhovRF7k9lgIiJiadYFWg8AtxO2fsDEPlYZ+XZ3JrnFZYbDeT6VES9Q2ayHRkfQLGkJlBVA007QZoDhZCIiUqVyDV/CO3RvGUp0swaUlrtYuj3dbC4voDLiBU57iSb2F9pbRETEk/S6FhwBkL4NW9rW6ks1elbNz1IZ8XC70nLZk55PgMPOJW1K4NAqwAZ9bjAdTUREThbcGLpeZr1OeIcrKi7VrN6bRXZBqcFgnk9lxMNVXqIZ1bUZYbs/tA52HAXhrQ2mEhGR06pcy7f1fTo1CaBHyzDKXW6WbEszm8vDqYx4MLfbzaLEVAAm9mkJiZXbv2vhqoiIR4oeAw0jofAY7FtadalmsS7V/CSVEQ+WkHyCpOxCgv0djG94AI4fgoBQ6HaF6WgiInI6Dj/ofZ31OuEdruhjbYAWf+AYGbnFBoN5NpURD1a5cHVcj0iCti+wDvacBAEh5kKJiMhPq3yS754viQosom/bRrjd8PnWVLO5PJjKiIdyutws3mL9xp3UszFs/8R6o/I3uYiIeKbIntAyBlxlsO1/VXuOLNqiMnImKiMe6rsDx8jMKyE82J+RznVQmgeN20PbIaajiYjIz6lc25fwDpf3aYnNBpsOH+fI8UKzuTyUyoiHqrxEc2mvFvhtrdhbJEZ7i4iIeIVek8HuD6kJRBYdYHCHJgB8punIaamMeKDSchdfVNwGNrkTcGCF9UaM9hYREfEKDZpClwnW68R3tAHaz1AZ8UAr92SSU1RG89BA+p34CnBD+xHQuJ3paCIicrYq1/glLuDSHs1w2G1sO5rLgcx8s7k8kMqIB6q8RHN57xbYt1ReornRYCIREamxTuMgpCkUZNAkdTXDO0UAVN2cINVURjxMYWk5S3dYD1W6oVU6HNsH/g2gx1WGk4mISI34BUDv663XJ12qWZiYgtvtNhjM86iMeJhlOzMoKnMS1SSYLqmLrIM9roTAhmaDiYhIzVU+yXfXZ4yPDiTAYWdfRj670/PM5vIwKiMepvISzaReTbFt+8g6qL1FRES8U4s+ENkLnKWE7V3I6K7NgOrnjolFZcSD5BSVsWJ3JgA3hG2FkhwIbwvthhtOJiIi58Rmq17zl3DSXTWJqbpUcxKVEQ/y5bY0Sp0uukQ2pPWhT6yDMVPArl8mERGv1ed6sDng6Ebimp0g2N9BUnYhW47kmE7mMfS3nAepvERzYzd/2L/MOqi7aEREvFvD5tB5HADBO94nrkckoEs1J1MZ8RAZecWs3Z8FwCS/NeB2QdRF0DTacDIRETlvJ+05MrF3c8C6xdfl0qUaUBnxGJ9vScXlhpg24TTe8z/roBauiojUD10ugaBGkJfCaP8dhAb6kZZbzMbDx00n8wgqIx6i8hLN7R1PQOYu8AuCnpOMZhIRkVriFwi9JwMQsG0B43u2AHSpppLKiAdIzi5kc9IJbDYYV1qxVqT7RAgKNxtMRERqT+W0e+diJnW39o76fGsq5U6XwVCeQWXEA1RuDTy8fSghuz+2DmrhqohI/dKqH0R0hfIihpSsonGIP8cKSok/cMx0MuNURjxA5SWau1vug6LjENoKOo42G0pERGqXzVY1HfHb8h6X9m4J6FINqIwYty8jj52pufjZbQzOWWIdjJkCdofZYCIiUvv6TAGbHZLiua59KQBLtqVRUu40HMwslRHDFiZYjfiKaD8CDnxtHYzRXTQiIvVSWEuIHgNATPYXNA8NJLe4nFV7sgwHM0tlxCC32111ieaO8I3gdkLrAdCsi+FkIiJywVSsCbRveY/Le1dsgLbFty/VqIwYtPVoDoeOFRLkb6dHxmfWwVgtXBURqde6XQ6B4ZCTzI2RSQB8vSOdolLfvVSjMmJQ5SWaWzvk4cjYBo4A6HWt4VQiInJB+QdDr6sB6JyyiNaNgikodfLt7gzDwcxRGTHE5XJX3dJ7Y+Bq62DXyyC4scFUIiJSJyrWBtp2LOSaXo0A376rRmXEkPWHsknLLaZxELQ7WnmJRgtXRUR8QtQgaBINZQVMabgZgG92ZZBXXGY4mBkqI4ZULlx9OOoQtsIsaNAcoscaTiUiInXCZqtaI9j60Md0bNaAknIXX+9MNxzMDJURA8qcLr7Yal2imcgK62Cf68HhZzCViIjUqT43ADZsh1ZzU8VNlIsSU41GMkVlxIDV+7I4XlhGdIMSmh79xjqoSzQiIr6lURR0GAnAJPtKAFbuyeREYanJVEaojBiwqOIuml+23ILNVQYtYyCyp+FUIiJS52JvAqDpvo/o3iKUcpebJdvSDIeqeyojday4zMmX263faBcXVTyht+I3o4iI+JjuV0BAQzh+kLvaW+tFfHEDNJWROvbNrgwKSp0MD8ukwbEtYPeHXpNNxxIRERMCGkCPSQCML7Uu28fvP0ZGXrHBUHVPZaSOVW509mDT9daBLhOgQVODiURExKiKNYMN9y1iUJsgXG74YqtvXapRGalDucVlfLM7AwdO+p/4yjqohasiIr6t7RBo1A5K87g/cifgexugqYzUoa+2p1Na7uL6xnvxL8qEkKbQaZzpWCIiYpLdXvUP0yF5X2GzwcbDxzl6oshwsLqjMlKHKjc6m9Yg3jrQ+3rwCzCYSEREPELMDQAEJq3k0ijrgXmf+dBCVpWROnIsv4Q1+7III59Ox637yfWEXhERAaBxe2g3HHBzV/gGwLc2QFMZqSOfb0vD6XJzT9Mt2J0lENkLWvQxHUtERDxFxT9Q+xz7HIcdth7N4WBWgeFQdeOcysjs2bNp3749QUFBDB48mPXr15/x3O3bt3PttdfSvn17bDYbzz///Llm9WqVG51NdlRs/x5zo/VsAhEREYAeV4F/CI7sfUyNygRgsY8sZK1xGVmwYAEzZszg8ccfZ/PmzcTExDBhwgQyMjJOe35hYSEdO3bkySefpEWLFucd2BulnChi/aFsOtpSiMzdCjaH9SwaERGRSoGh0P1KAG4OWgP4zgZoNS4jzz33HHfddRfTpk2jR48ezJkzh5CQEObNm3fa8wcOHMg//vEPbrjhBgIDA887sDdaXPGb6aEm1nVAOo+Dhs0NJhIREY9UcammY9qXNHSUsyc9n91peYZDXXg1KiOlpaVs2rSJuLi46m9gtxMXF0d8fHythSopKSE3N/eUD2+2MDEFOy7GO5dbB2K0cFVERE6j/UgIa4OtJIeHWu8FfGPPkRqVkaysLJxOJ5GRkaccj4yMJC2t9naLmzVrFuHh4VUfUVFRtfa969qBzHy2Hc1luGM7DYrTIagRdL3UdCwREfFEdnvVbb6TbMsB61KN2+02GOrC88i7aWbOnElOTk7VR3JysulI56xyb5F7wysW+faeDH6+eblKRETOQsUGaM0z1tDWP5fDxwrZejTHcKgLq0ZlJCIiAofDQXp6+inH09PTa3VxamBgIGFhYad8eCO3283CxBQaUsigYmsxkrZ/FxGRn9Q0GqIGY3O7eCQyAaj/l2pqVEYCAgLo378/y5YtqzrmcrlYtmwZQ4YMqfVw3m57Si4HMgu4yn89fq5iiOgKrfqZjiUiIp6u4h+u40qXAW4Wb0nF5aq/l2pqfJlmxowZzJ07l9dff52dO3dy3333UVBQwLRp0wCYOnUqM2fOrDq/tLSUhIQEEhISKC0t5ejRoyQkJLBv377a+1l4qMome1vl9u+x2ltERETOQs+rwS+I0Ny9DApMJjWnmM1Jx02numBqXEamTJnCM888w2OPPUZsbCwJCQksWbKkalFrUlISqanVW9impKTQt29f+vbtS2pqKs888wx9+/blzjvvrL2fhQdyudwsSkyhrS2dzsVbwWaHPlNMxxIREW8QFA7dLgfgoSbfAfX7Uo3N7QVLdHNzcwkPDycnJ8dr1o9sPJTN5Dnx/C7wI+6z/Q+ix8ItH5mOJSIi3mLf1/DWtZQFNKJn7r8Ia9iAdTPH4ufwyHtPTuts//72np+Rl1mYmIINF1MCVlsHtHBVRERqouPFENoS/9ITXBG8laz8Ur47mG061QWhMnIBlDtdfL41lcH2XTQpS4PA6nGbiIjIWbE7qi7v3xm6Dqi/l2pURi6AtfuPkZVfyo2VU5FeV4N/sNlQIiLifSqm6t3y1tGUHL7YlkZpuctwqNqnMnIBLExMIYRiLrFbi46I0SUaERE5B826Quv+2N3l3BSynpyiMlbvyzSdqtapjNSy4jInX25L4xL7egJdRdAkGqIGmY4lIiLequJ5ZjcGWtP2RYmpP3W2V1IZqWXLd2eSV1LOLwIrF65qbxERETkPva4FRwAti/bS3XaYr7anUVzmNJ2qVqmM1LJFiSm0JpMB7m2ADfrcYDqSiIh4s5AmVQ9YvTVkLQWlTr7dlWE4VO1SGalF+SXlfL0znWscq6wDHUZCI+994rCIiHiIirWHE22r8aOcRVvq1101KiO1aOmONErKnUwJ0EPxRESkFnUaCw2a06D8OKPsiSzbmUF+SbnpVLVGZaQWLUpMpb9tD23cqRDQELpPNB1JRETqA4c/9LkegKnBaykpd/H1jnTDoWqPykgtOV5Qyso9mUx2rLQO9JgEAQ2MZhIRkXqk4q6a4a4NNCKvXm2ApjJSS77Yloafq5gr/Sr2FtElGhERqU0tekGLPjjc5Ux0xLNybyYnCktNp6oVKiO1ZGHiUcbbN9KAQmjUDtoOMR1JRETqm9ibALglaDVlTjdfbk8zHKh2qIzUgrScYr47mF19iSbmRrDr/1oREallvSeD3Y8uzn10th2pNxug6W/MWrB4SwqR7mMMd2yzDsRobxEREbkAGkRA5wkAXOtYydr9WWTmlRgOdf5URmrBosQUrnaswY4b2g2DJh1MRxIRkfqqYk3i9QFrsbmdfLHN+6cjKiPn6VBWAYlHTjDZscI6oIWrIiJyIXUeD8FNaOLKZoR9a724q0Zl5DwtSkwh1rafaHsq+IdAj6tMRxIRkfrML6Bqz5FrHSvZcOg4KSeKDIc6Pyoj58HtdrMwMYVrKxeudr8SAkPNhhIRkfqvYs+RCY5NhFHAZ1u8+1KNysh52J2eR1JGNlc64q0DsTeaDSQiIr6hZQw070kAZVzhWOf1z6pRGTkPCxNSGGvfTLitAMLaQPuRpiOJiIgvsNmq/gE82bGSLUdyOJRVYDjUuVMZOUdut5tFW1JO2lvkBu0tIiIidaf39WBz0M++l462FD7b6r2XavS35zn6PvkExdkpjLRvsQ7E6BKNiIjUodBI6BQHwDWOVV59V43KyDlamJDCJMca/GwuiBoMEZ1MRxIREV9TcanmWscq9qTlsCc9z3Cgc6Mycg6cLjefbUnhWscq64CmIiIiYkKXSyGoES1t2Qyxb2exl05HVEbOwboDx2hesJtu9mTcfkHQ82rTkURExBf5B0GvawFrOrJoSyput9twqJpTGTkHCxOqF67aul0OwY3MBhIREd9V8STfS+3ryczKZHtKruFANacyUkMl5U6WbkvmKsca60CMtn8XERGDWveDiC4E20q51LHeKxeyqozU0Mo9WQws3UATWz7u0JYQfbHpSCIi4ststqrnok12rGTxllRcLu+6VKMyUkOLTtr+3dbnerA7DCcSERGf12cKbpudwfZdOHIO8X3ycdOJakRlpAYKS8vZuGMvF9sTrAO6RCMiIp4grBW2jqOBioWsid61AZrKSA18vTODCa6V+NucuFv1g+bdTEcSERGxVCxkvca+is8Sj+L0oks1KiM1sDChem8RW6ymIiIi4kG6XY47MJQoeyYdC7fw3YFjphOdNZWRs5RTWEbang30sh/CZQ+ouq9bRETEI/gHY+t5DQCTHSu86km+KiNnacn2VK6yWQtX7V0vgZAmhhOJiIj8QMXU/jLHdyzfepDScpfhQGdHZeQsfZaQxCTHauuTiutyIiIiHiVqMO4mHWlgK2FIyVrW7MsyneisqIychYy8YgIOfUszWy7O4AjoNNZ0JBERkR+z2bBV3Ol5rRc9yVdl5Cx8tiWVa+zWJRpH7A3g8DecSERE5AxipgAwzLGdrTu2UVzmNBzo56mMnIVvvt/NWPtm6xM9oVdERDxZo7a4248EYEL5cpbvzjAc6OepjPyM5OxC2qUuIdBWTlnz3tCil+lIIiIiP6ly+4lrHStZlOD5l2pURn7Goi0pTHasAMC/nxauioiIF+hxJU7/BnSwp5O9exX5JeWmE/0klZGfkbBpHbH2A7hsftD7OtNxREREfl5AA+w9rwJgons5y3amGw7001RGfsLe9Dz6HV8CgDN6HDSIMJxIRETk7NgqtqG4wrGOJd8fNJzmp6mM/IRFCclVe4v499clGhER8SJth1IWGkWYrYig/V+QU1hmOtEZqYycgdvtJnXzF7SwHackoBF0nmA6koiIyNmz26vWOl5tW8GX29MMBzozlZEz2HIkhxGFSwGw974O/AIM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5JPYbDYeeeQR01F81tGjR7n55ptp2rQpwcHB9O7dm40bN5qO5bOcTid/+tOf6NChA8HBwURHR/O3v/3tZ5+/Imfms2VkwYIFzJgxg8cff5zNmzcTExPDhAkTyMjIMB3N56xYsYIHHniAdevWsXTpUsrKyhg/fjwFBQWmo/m8DRs28J///Ic+ffqYjuKzjh8/zrBhw/D39+eLL75gx44dPPvsszRu3Nh0NJ/11FNP8fLLL/Piiy+yc+dOnnrqKZ5++mleeOEF09G8ls/e2jt48GAGDhzIiy++CFjPv4mKiuKhhx7i0UcfNZzOt2VmZtK8eXNWrFjByJEjTcfxWfn5+fTr14+XXnqJ//u//yM2Npbnn3/edCyf8+ijj7JmzRpWrVplOopUuOKKK4iMjOTVV1+tOnbttdcSHBzMW2+9ZTCZ9/LJyUhpaSmbNm0iLi6u6pjdbicuLo74+HiDyQQgJycHgCZNmhhO4tseeOABLr/88lP+O5G6t3DhQgYMGMB1111H8+bN6du3L3PnzjUdy6cNHTqUZcuWsWfPHgASExNZvXo1l156qeFk3ssrHpRX27KysnA6nURGRp5yPDIykl27dhlKJWBNqB555BGGDRtGr169TMfxWe+99x6bN29mw4YNpqP4vAMHDvDyyy8zY8YMfv/737NhwwYefvhhAgICuPXWW03H80mPPvooubm5dOvWDYfDgdPp5IknnuCmm24yHc1r+WQZEc/1wAMPsG3bNlavXm06is9KTk5m+vTpLF26lKCgINNxfJ7L5WLAgAH8/e9/B6Bv375s27aNOXPmqIwY8v777/P222/zzjvv0LNnTxISEnjkkUdo1aqVfk3OkU+WkYiICBwOB+np6accT09Pp0WLFoZSyYMPPsjixYtZuXIlbdq0MR3HZ23atImMjAz69etXdczpdLJy5UpefPFFSkpKcDgcBhP6lpYtW9KjR49TjnXv3p0PP/zQUCL5zW9+w6OPPsoNN9wAQO/evTl8+DCzZs1SGTlHPrlmJCAggP79+7Ns2bKqYy6Xi2XLljFkyBCDyXyT2+3mwQcf5OOPP+abb76hQ4cOpiP5tLFjx7J161YSEhKqPgYMGMBNN91EQkKCikgdGzZs2I9udd+zZw/t2rUzlEgKCwux20/969PhcOByuQwl8n4+ORkBmDFjBrfeeisDBgxg0KBBPP/88xQUFDBt2jTT0XzOAw88wDvvvMOnn35KaGgoaWlpAISHhxMcHGw4ne8JDQ390XqdBg0a0LRpU63jMeCXv/wlQ4cO5e9//zvXX38969ev55VXXuGVV14xHc1nTZw4kSeeeIK2bdvSs2dPvv/+e5577jluv/1209G8l9uHvfDCC+62bdu6AwIC3IMGDXKvW7fOdCSfBJz2Y/78+aajSYVRo0a5p0+fbjqGz1q0aJG7V69e7sDAQHe3bt3cr7zyiulIPi03N9c9ffp0d9u2bd1BQUHujh07uv/whz+4S0pKTEfzWj67z4iIiIh4Bp9cMyIiIiKeQ2VEREREjFIZEREREaNURkRERMQolRERERExSmVEREREjFIZEREREaNURkRERMQolRERERExSmVEREREjFIZEREREaNURkRERMSo/wesncfHav45FAAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "plt.plot(vqap_solution)\n", - "plt.plot(ref_sol)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.8.13 ('test_qalcore')", - "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.8.13" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "b801f20f58c2a55eba63eb4bd542f58d8849c5838c1257501c707620be8344ae" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/example/qiskit/vqees/vqees.ipynb b/example/qiskit/vqees/vqees.ipynb deleted file mode 100644 index ef80186..0000000 --- a/example/qiskit/vqees/vqees.ipynb +++ /dev/null @@ -1,230 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from qalcore.qiskit.vqfd.vqees import VQAP_IE, VQEES\n", - "from qiskit.circuit.library.n_local.real_amplitudes import RealAmplitudes\n", - "from qiskit.algorithms.optimizers import COBYLA\n", - "from qiskit.quantum_info import Statevector\n", - "from qiskit import Aer\n", - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "nqbits = 3\n", - "size = 2**nqbits" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# define the initial condition\n", - "x = np.linspace(0,1,size+2)\n", - "dx = x[1]-x[0]\n", - "u0 = np.sin(np.pi*x)[1:-1]\n", - "u0 /= np.linalg.norm(u0)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# define the time steps\n", - "dt = 0.01\n", - "delta_x = dt/dx/dx" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "# compute the VQLS solution\n", - "ansatz = RealAmplitudes(nqbits, entanglement=\"full\", reps=3, insert_barriers=False)\n", - "vqap = VQAP_IE(\n", - " delta_x= delta_x,\n", - " ansatz=ansatz,\n", - " boundary='Dirichlet',\n", - " optimizer=COBYLA(maxiter=200, disp=True),\n", - " quantum_instance=Aer.get_backend(\"aer_simulator_statevector\"),\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/nico/miniconda3/envs/test_qalcore/lib/python3.8/site-packages/scipy/optimize/_cobyla_py.py:273: ComplexWarning: Casting complex values to real discards the imaginary part\n", - " xopt, info = cobyla.minimize(calcfc, m=m, x=np.copy(x0), rhobeg=rhobeg,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - " Return from subroutine COBYLA because the MAXFUN limit has been reached.\n", - "\n", - " NFVALS = 200 F =-1.430358E-01 MAXCV = 0.000000E+00\n", - " X = 3.093939E-02 -2.198688E+00 2.347095E+00 1.561557E+00 -8.054361E-01\n", - " 1.928710E+00 -1.894439E+00 1.955355E+00 -1.748264E+00 2.640764E+00\n", - " -9.569196E-01 3.061099E+00\n", - "1\n", - "\n", - " Return from subroutine COBYLA because the MAXFUN limit has been reached.\n", - "\n", - " NFVALS = 200 F =-1.778359E-01 MAXCV = 0.000000E+00\n", - " X =-1.432474E+00 -6.421890E-01 8.459900E-01 -7.554346E-01 3.662625E+00\n", - " 8.403747E-01 -1.071505E+00 2.511153E-01 -8.876786E-01 1.958141E+00\n", - " 4.479237E+00 -1.165457E+00\n", - "2\n", - "\n", - " Return from subroutine COBYLA because the MAXFUN limit has been reached.\n", - "\n", - "3\n", - " NFVALS = 200 F =-1.782814E-01 MAXCV = 0.000000E+00\n", - " X =-1.264424E+00 1.423378E+00 1.531451E+00 8.281044E-01 3.007585E+00\n", - " 3.028427E-01 2.442947E+00 -1.202558E+00 2.067987E+00 -1.416959E+00\n", - " 1.062891E+00 2.006972E+00\n", - "4\n", - "\n", - " Return from subroutine COBYLA because the MAXFUN limit has been reached.\n", - "\n", - " NFVALS = 200 F =-1.782616E-01 MAXCV = 0.000000E+00\n", - " X = 3.778322E-01 1.768555E+00 -1.863519E+00 3.551437E+00 -1.592131E+00\n", - " 2.094611E+00 3.056376E+00 2.789313E+00 7.794637E-01 1.553244E+00\n", - " -1.713484E+00 1.794100E+00\n", - "\n", - " Return from subroutine COBYLA because the MAXFUN limit has been reached.\n", - "\n", - " NFVALS = 200 F =-1.712297E-01 MAXCV = 0.000000E+00\n", - " X =-2.521190E-02 7.252967E-01 2.267406E+00 4.841525E-02 -1.609614E+00\n", - " -1.784227E+00 1.846478E+00 -2.681573E+00 -3.151360E+00 2.461445E+00\n", - "5\n", - " -1.289201E+00 1.889350E+00\n", - "\n", - " Return from subroutine COBYLA because the MAXFUN limit has been reached.\n", - "\n", - " NFVALS = 200 F =-1.781753E-01 MAXCV = 0.000000E+00\n", - " X =-4.363277E-01 2.449191E+00 -2.698352E+00 -1.230914E+00 1.638418E+00\n", - " -1.268450E+00 1.207758E+00 2.281432E+00 3.735218E+00 1.452060E+00\n", - " -1.625384E+00 -6.209779E-02\n", - "6\n", - "\n", - " Return from subroutine COBYLA because the MAXFUN limit has been reached.\n", - "\n", - "7\n", - " NFVALS = 200 F =-1.783887E-01 MAXCV = 0.000000E+00\n", - " X = 4.594587E+00 2.232453E-02 2.064498E+00 -2.791311E+00 2.051147E+00\n", - " 2.642447E+00 2.742485E+00 -1.059590E+00 -5.453797E-03 3.548029E+00\n", - " -9.570506E-01 -3.143381E+00\n", - "8\n", - " Return from subroutine COBYLA because the MAXFUN limit has been reached.\n", - "\n", - " NFVALS = 200 F =-1.784158E-01 MAXCV = 0.000000E+00\n", - " X = 1.610252E+00 -1.187604E+00 3.509035E-01 2.546416E+00 -1.544553E+00\n", - " 1.428876E+00 -1.118566E+00 2.572413E+00 -1.956171E+00 3.571697E+00\n", - " -1.208261E+00 -3.175544E+00\n", - "\n", - "\n", - " Return from subroutine COBYLA because the MAXFUN limit has been reached.\n", - "\n", - " NFVALS = 200 F =-1.783334E-01 MAXCV = 0.000000E+00\n", - " X = 3.329608E+00 -9.951617E-02 -1.655784E+00 2.019546E+00 -1.761426E+00\n", - " -3.224726E+00 1.396132E+00 1.764120E+00 6.894861E-01 1.267433E+00\n", - " -1.404854E+00 6.676899E-01\n", - "9\n", - "\n", - " Return from subroutine COBYLA because the MAXFUN limit has been reached.\n", - "\n", - " NFVALS = 200 F =-1.782255E-01 MAXCV = 0.000000E+00\n", - " X = 3.025373E+00 -1.506018E+00 -1.899606E+00 1.208027E-01 -6.862746E-01\n", - " -2.504989E+00 3.247963E+00 4.258424E-01 -1.030954E-01 1.524788E+00\n", - " -9.690393E-01 5.973376E-01\n" - ] - } - ], - "source": [ - "# solve with vqap\n", - "vqees = VQEES(vqap)\n", - "solution = vqees.solve(u0, tmax = 0.1 dt=dt)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "for s in solution:\n", - " plt.plot(x, np.insert(s, [0,2**nqbits], [0,0])) " - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.8.13 ('test_qalcore')", - "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.8.13" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "b801f20f58c2a55eba63eb4bd542f58d8849c5838c1257501c707620be8344ae" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/example/dwave/qubols/qubols.ipynb b/example/qubols/qubols.ipynb similarity index 99% rename from example/dwave/qubols/qubols.ipynb rename to example/qubols/qubols.ipynb index b665524..3cc6f99 100644 --- a/example/dwave/qubols/qubols.ipynb +++ b/example/qubols/qubols.ipynb @@ -121,8 +121,8 @@ "metadata": {}, "outputs": [], "source": [ - "from qalcore.dwave.qubols.qubols import QUBOLS\n", - "from qalcore.dwave.qubols.encodings import RealQbitEncoding, RealUnitQbitEncoding, EfficientEncoding\n", + "from qalcore.qubols import QUBOLS\n", + "from qalcore.qubols import RealQbitEncoding, RealUnitQbitEncoding, EfficientEncoding\n", "options = {'num_reads':100, 'num_qbits':21, 'encoding':EfficientEncoding}\n", "qubols = QUBOLS(options)\n", "sol_num = qubols.solve(A, b)" diff --git a/example/qiskit/vqls/vqls.ipynb b/example/vqls/vqls.ipynb similarity index 100% rename from example/qiskit/vqls/vqls.ipynb rename to example/vqls/vqls.ipynb diff --git a/example/qiskit/vqls/vqls.py b/example/vqls/vqls.py similarity index 100% rename from example/qiskit/vqls/vqls.py rename to example/vqls/vqls.py diff --git a/example/qiskit/vqls/vqls_poisson.ipynb b/example/vqls/vqls_poisson.ipynb similarity index 99% rename from example/qiskit/vqls/vqls_poisson.ipynb rename to example/vqls/vqls_poisson.ipynb index b8fb433..2337afc 100644 --- a/example/qiskit/vqls/vqls_poisson.ipynb +++ b/example/vqls/vqls_poisson.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "from qalcore.qiskit.vqls.vqls import VQLS\n", + "from qalcore.vqls import VQLS\n", "from qiskit.circuit.library.n_local.real_amplitudes import RealAmplitudes\n", "from qiskit.algorithms.optimizers import COBYLA\n", "from qiskit.quantum_info import Statevector\n", diff --git a/example/qiskit/vqls/vqls_runtime.py b/example/vqls/vqls_runtime.py similarity index 69% rename from example/qiskit/vqls/vqls_runtime.py rename to example/vqls/vqls_runtime.py index a2e8bdb..aab7d15 100644 --- a/example/qiskit/vqls/vqls_runtime.py +++ b/example/vqls/vqls_runtime.py @@ -1,4 +1,4 @@ -from qalcore.qiskit.vqls import VQLS +from qalcore.vqls import VQLS from qiskit.circuit.library.n_local.real_amplitudes import RealAmplitudes from qiskit.algorithms.optimizers import COBYLA, ADAM import numpy as np @@ -7,8 +7,13 @@ from qiskit.quantum_info import Statevector # from qiskit.primitives import Estimator, Sampler, BackendEstimator -from qiskit_ibm_runtime import QiskitRuntimeService, Estimator, Sampler, Session, Options - +from qiskit_ibm_runtime import ( + QiskitRuntimeService, + Estimator, + Sampler, + Session, + Options, +) # define the problem @@ -20,8 +25,7 @@ # define ansatz ansatz = RealAmplitudes(2, entanglement="full", reps=3, insert_barriers=False) -opts = {"use_overlap_test": False, - "use_local_cost_function": False} +opts = {"use_overlap_test": False, "use_local_cost_function": False} # define the runtime service = QiskitRuntimeService() @@ -36,22 +40,17 @@ estimator = Estimator(session=session, options=options) # Sampler = Sampler(session=session, options=options) - vqls = VQLS( - estimator, - ansatz, - ADAM(maxiter=5, disp=True), - options=opts - ) - + vqls = VQLS(estimator, ansatz, ADAM(maxiter=5, disp=True), options=opts) + res = vqls.solve(A, b) -classical_solution = np.linalg.solve(A,b) +classical_solution = np.linalg.solve(A, b) -ref_solution = classical_solution/ np.linalg.norm(classical_solution) +ref_solution = classical_solution / np.linalg.norm(classical_solution) vqls_solution = np.real(Statevector(res.state).data) plt.scatter(ref_solution, vqls_solution) plt.plot([-1, 1], [-1, 1], "--") -plt.show() \ No newline at end of file +plt.show() diff --git a/qalcore/dwave/__init__.py b/qalcore/dwave/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qalcore/dwave/qubols/__init__.py b/qalcore/dwave/qubols/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qalcore/dwave/qubols/embedded_qubols.py b/qalcore/dwave/qubols/embedded_qubols.py deleted file mode 100644 index 08c3160..0000000 --- a/qalcore/dwave/qubols/embedded_qubols.py +++ /dev/null @@ -1,110 +0,0 @@ -from sympy import Symbol -from sympy.matrices import Matrix -import numpy as np -from qalcore.dwave.qubols.encodings import RealUnitQbitEncoding -from typing import Optional, Union, List, Callable, Dict, Tuple -from dwave.system import DWaveSampler , EmbeddingComposite -import neal -from dimod import ExactSolver -from functools import partial -from dwave.embedding.chain_strength import uniform_torque_compensation -import dwave_networkx as dnx -from minorminer import find_embedding -from dwave.embedding import embed_qubo, majority_vote, chain_break_frequency -from .solution_vector import SolutionVector -from .qubols import QUBOLS - -class EmbeddedQUBOLS(QUBOLS): - - def __init__(self, options: Optional[Union[Dict, None]] = None): - """Linear Solver using QUBO - - Args: - options: dictionary of options for solving the linear system - """ - - self.default_solve_options = { - "sampler": neal.SimulatedAnnealingSampler(), - "encoding": RealUnitQbitEncoding, - "num_qbits": 11, - "num_reads": 100, - "verbose": False, - "chain_strength": None, - "target_graph": dnx.chimera_graph(16), - "threshold": None - } - self.options = self._validate_solve_options(options) - self.sampler = self.options.pop('sampler') - self.target_graph = self.options.pop("target_graph") - - - def create_embedded_qubo_dict(self): - """Embed the qubo dictionary on a target graph - """ - - # find the embedding - embedding = find_embedding(self.qubo_dict, self.target_graph) - - # embed the qubo - embedded_qubo_dict = embed_qubo(self.qubo_dict, embedding, self.target_graph, - chain_strength=self.options["chain_strength"]) - - # convert to linear indexes - idx_translate = {} - count = 0 - for k, v in embedding.items(): - for idx in v: - idx_translate[idx] = count - count += 1 - - # translate the embedding - chains = [] - for k, v in embedding.items(): - new_idx = [idx_translate[idx] for idx in v] - embedding[k] = new_idx - chains.append(new_idx) - - - embedded_qubo_dict_tr = {} - for k,v in embedded_qubo_dict.items(): - embedded_qubo_dict_tr [ (idx_translate[k[0]], idx_translate[k[1]]) ] = v - - return (embedded_qubo_dict_tr, - embedding, - chains) - - - def solve(self, - matrix: np.ndarray, - vector: np.ndarray ): - """Solve the linear system - - Args: - sampler (_type_, optional): _description_. Defaults to neal.SimulatedAnnealingSampler(). - encoding (_type_, optional): _description_. Defaults to RealUnitQbitEncoding. - nqbit (int, optional): _description_. Defaults to 10. - - Returns: - _type_: _description_ - """ - - self.A = matrix - self.b = vector - self.size = self.A.shape[0] - - sol = SolutionVector(size=self.size, - nqbit=self.options['num_qbits'], - encoding=self.options['encoding']) - self.x = sol.create_polynom_vector() - self.qubo_dict = self.create_qubo_matrix(self.x, prec=self.options["threshold"]) - - self.embedded_qubo_dict, self.embedding, self.chains = self.create_embedded_qubo_dict() - - self.sampleset = self.sampler.sample_qubo(self.embedded_qubo_dict, num_reads = self.options['num_reads']) - lowest_sol = self.sampleset.lowest() - self.chain_break = chain_break_frequency(self.sampleset.record.sample, self.embedding) - lowest_sol, _ = majority_vote(lowest_sol.record[0][0], self.chains) - - return sol.decode_solution(lowest_sol[0]) - - diff --git a/qalcore/dwave/qubols/encodings.py b/qalcore/dwave/qubols/encodings.py deleted file mode 100644 index 8ce716e..0000000 --- a/qalcore/dwave/qubols/encodings.py +++ /dev/null @@ -1,163 +0,0 @@ -from sympy import Symbol -from sympy.matrices import Matrix -import numpy as np - - -class BaseQbitEncoding(object): - - def __init__(self, nqbit, var_base_name): - """Encode a single real number in a - - Args: - nqbit (int): number of qbit required in the expansion - var_base_name (str): base names of the different qbits - only_positive (bool, optional): Defaults to False. - """ - self.nqbit = nqbit - self.var_base_name = var_base_name - self.variables = self.create_variable() - - - def create_variable(self): - """Create all the variabes/qbits required for the expansion - - Returns: - list: list of Symbol - """ - variables = [] - for i in range(self.nqbit): - variables.append(Symbol(self.var_base_name + '_%03d' %(i+1))) - return variables - -class EfficientEncoding(BaseQbitEncoding): - - def __init__(self, nqbit, var_base_name): - super().__init__(nqbit, var_base_name) - self.base_exponent = 0 - self.int_max = 2**(nqbit-1)-1 - - def create_polynom(self): - """ - Create the polynoms of the expansion - - Returns: - sympy expression - """ - out = -2**(self.nqbit-1) * self.variables[0] - for i in range(self.nqbit-1): - out += 2**(i) * self.variables[i+1] - return out/self.int_max - - def decode_polynom(self, data): - """ - Create the polynoms of the expansion - - Returns: - sympy expression - """ - out = -2**(self.nqbit-1) * data[0] - for i in range(self.nqbit-1): - out += 2**(i) * data[i+1] - return out/self.int_max - -class RealQbitEncoding(BaseQbitEncoding): - - def __init__(self, nqbit, var_base_name): - super().__init__(nqbit, var_base_name) - self.base_exponent = 0 - - def create_polynom(self): - """ - Create the polynoms of the expansion - - Returns: - sympy expression - """ - out = 0.0 - for i in range(self.nqbit//2): - out += 2**(i-self.base_exponent) * self.variables[i] - out -= 2**(i-self.base_exponent) * self.variables[self.nqbit//2+i] - return out - - def decode_polynom(self, data): - out = 0.0 - for i in range(self.nqbit//2): - out += 2**(i-self.base_exponent) * data[i] - out -= 2**(i-self.base_exponent) * data[self.nqbit//2+i] - return out - -class RealUnitQbitEncoding(BaseQbitEncoding): - - def __init__(self, nqbit, var_base_name): - super().__init__(nqbit, var_base_name) - self.base_exponent = 0 - self.int_max = None - assert((nqbit-1)%2==0) - - def find_int_max(self): - """Find the amx value of the encoding - """ - i = 0 - self.int_max = 2**(i-self.base_exponent) - - for i in range(1, (self.nqbit-1)//2): - self.int_max += 2**(i-self.base_exponent) - - - def create_polynom(self): - """ - Create the polynoms of the expansion - - Returns: - sympy expression - """ - out = 0.0 - - self.find_int_max() - - i = 0 - out += 2**(i-self.base_exponent)/self.int_max * self.variables[i] - - for i in range(1, (self.nqbit-1)//2+1): - - out += 2**(i-self.base_exponent)/self.int_max * self.variables[i] - out -= 2**(i-self.base_exponent)/self.int_max * self.variables[(self.nqbit-1)//2+i] - return out - - def decode_polynom(self, data): - out = 0.0 - - if self.int_max is None: - self.find_int_max() - - i=0 - out += 2**(i-self.base_exponent)/self.int_max * data[i] - - for i in range(1, (self.nqbit-1)//2+1): - out += 2**(i-self.base_exponent)/self.int_max * data[i] - out -= 2**(i-self.base_exponent)/self.int_max * data[(self.nqbit-1)//2+i] - return out - -class PositiveQbitEncoding(BaseQbitEncoding): - - def __init__(self, nqbit, var_base_name): - super().__init__(nqbit, var_base_name) - - def create_polynom(self): - """ - Create the polynoms of the expansion - - Returns: - sympy expression - """ - out = 0.0 - for i in range(self.nqbit): - out += 2**i * self.variables[i] - return out - - def decode_polynom(self, data): - out = 0.0 - for i in range(self.nqbit//2): - out += 2**i * data[i] - out -= 2**i * data[self.nqbit//2+i] - return out \ No newline at end of file diff --git a/qalcore/dwave/qubols/qubols.py b/qalcore/dwave/qubols/qubols.py deleted file mode 100644 index ef4f3d1..0000000 --- a/qalcore/dwave/qubols/qubols.py +++ /dev/null @@ -1,145 +0,0 @@ -from sympy import Symbol -from sympy.matrices import Matrix, SparseMatrix -import numpy as np -from qalcore.dwave.qubols.encodings import RealUnitQbitEncoding -from typing import Optional, Union, List, Callable, Dict, Tuple -from dwave.system import DWaveSampler , EmbeddingComposite -import neal -from dimod import ExactSolver -import scipy.sparse as spsp -from .solution_vector import SolutionVector - -class QUBOLS: - - def __init__(self, options: Optional[Union[Dict, None]] = None): - """Linear Solver using QUBO - - Args: - options: dictionary of options for solving the linear system - """ - - self.default_solve_options = { - "sampler": neal.SimulatedAnnealingSampler(), - "encoding": RealUnitQbitEncoding, - "num_qbits": 11, - "num_reads": 100, - "verbose": False - } - self.options = self._validate_solve_options(options) - self.sampler = self.options.pop('sampler') - - def _validate_solve_options(self, options: Union[Dict, None]) -> Dict: - """validate the options used for the solve methods - - Args: - options (Union[Dict, None]): options - """ - valid_keys = self.default_solve_options.keys() - - if options is None: - options = self.default_solve_options - - else: - for k in options.keys(): - if k not in valid_keys: - raise ValueError( - "Option {k} not recognized, valid keys are {valid_keys}" - ) - for k in valid_keys: - if k not in options.keys(): - options[k] = self.default_solve_options[k] - - return options - - - def solve(self, - matrix: np.ndarray, - vector: np.ndarray ): - """Solve the linear system - - Args: - sampler (_type_, optional): _description_. Defaults to neal.SimulatedAnnealingSampler(). - encoding (_type_, optional): _description_. Defaults to RealUnitQbitEncoding. - nqbit (int, optional): _description_. Defaults to 10. - - Returns: - _type_: _description_ - """ - - self.A = matrix - self.b = vector - self.size = self.A.shape[0] - - sol = SolutionVector(size=self.size, - nqbit=self.options['num_qbits'], - encoding=self.options['encoding']) - self.x = sol.create_polynom_vector() - self.qubo_dict = self.create_qubo_matrix(self.x) - - self.sampleset = self.sampler.sample_qubo(self.qubo_dict, num_reads = self.options['num_reads']) - self.lowest_sol = self.sampleset.lowest() - return sol.decode_solution(self.lowest_sol.record[0][0]) - - def create_qubo_matrix(self, x, prec=None): - """Create the QUBO dictionary requried by dwave solvers - to solve the linear system - - A x = b - - Args: - Anp (np.array): matrix of the linear system - bnp (np.array): righ hand side of the linear system - x (sympy.Matrix): unknown - - Returns: - _type_: _description_ - """ - if isinstance(self.A, spsp.spmatrix): - A = SparseMatrix(*self.A.shape, dict(self.A.todok().items())) - else: - A = Matrix(self.A) - - if isinstance(self.b, spsp.spmatrix): - b = SparseMatrix(*self.b.shape, dict(self.b.todok().items())) - else: - b = Matrix(self.b) - - polynom = x.T @ A.T @ A @ x - x.T @ A.T @ b - b.T@ A @ x + b.T @ b - polynom = polynom[0] - polynom = polynom.expand() - polynom = polynom.as_ordered_terms() - - out = dict() - - for term in polynom: - m = term.args - if len(m) == 0: - continue - - if len(m) == 2: - varname = str(m[1]) - varname = varname.split("**")[0] - key = (varname , varname) - - elif len(m) == 3: - key = (str(m[1]),str(m[2])) - - if key not in out: - out[key] = 0.0 - - out[key] += m[0] - - if prec is None: - return out - - elif prec is not None: - nremoved = 0 - out_cpy = dict() - for k, v in out.items(): - if np.abs(v)>prec: - out_cpy[k] = v - else: - nremoved += 1 - print('Removed %d elements' %nremoved) - return out_cpy - diff --git a/qalcore/dwave/qubols/solution_vector.py b/qalcore/dwave/qubols/solution_vector.py deleted file mode 100644 index 009e69a..0000000 --- a/qalcore/dwave/qubols/solution_vector.py +++ /dev/null @@ -1,58 +0,0 @@ -from sympy import Symbol -from sympy.matrices import Matrix -import numpy as np -from qalcore.dwave.qubols.encodings import RealUnitQbitEncoding -from dwave.system import DWaveSampler , EmbeddingComposite -import neal -from dimod import ExactSolver - -class SolutionVector(object): - - def __init__(self, size, nqbit, encoding, base_name = 'x'): - """Encode the solution vector in a list of RealEncoded - - Args: - size (int): number of unknonws in the vector (i.e. size of the system) - nqbit (int): number of qbit required per unkown - base_name (str, optional): base name of the unknowns Defaults to 'x'. - only_positive (bool, optional): Defaults to False. - """ - self.size = size - self.nqbit = nqbit - self.base_name = base_name - self.encoding = encoding - self.encoded_reals = self.create_encoding() - - def create_encoding(self): - """Create the eocnding for all the unknowns - - - Returns: - list[RealEncoded]: - """ - encoded_reals = [] - for i in range(self.size): - var_base_name = self.base_name + '_%03d' %(i+1) - encoded_reals.append(self.encoding(self.nqbit, var_base_name)) - - return encoded_reals - - def create_polynom_vector(self): - """Create the list of polynom epxressions - - Returns: - sympy.Matrix: matrix of polynomial expressions - """ - pl = [] - for real in self.encoded_reals: - pl.append(real.create_polynom()) - - return Matrix(pl) - - def decode_solution(self, data): - - sol = [] - for i, real in enumerate(self.encoded_reals): - local_data = data[i*self.nqbit:(i+1)*self.nqbit] - sol.append(real.decode_polynom(local_data)) - return np.array(sol) \ No newline at end of file diff --git a/qalcore/pennylane/__init__.py b/qalcore/pennylane/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qalcore/pennylane/data.py b/qalcore/pennylane/data.py deleted file mode 100644 index cc57aca..0000000 --- a/qalcore/pennylane/data.py +++ /dev/null @@ -1,82 +0,0 @@ -import numpy as np -from dataclasses import dataclass - - - - -@dataclass -class DataSet: - npts: int - features: np.array - labels: np.array - -def read_dataset(features, labels, shuffle=False): - """Read the data set - - Args: - dataset (str, optional): dataset filename. Defaults to '../data/htru2/HTRU_2.csv'. - delimiter (str, optional): delimiter to read dataset. Defaults to ','. - - Returns: - DataSet: Dataclass containing the dataset - """ - - features = np.load(features) - labels = np.load(labels) - npts = len(labels) - idx = np.arange(npts) - if shuffle: - np.random.shuffle(idx) - dataset = DataSet(npts = npts, features= features[idx,:], labels= labels[idx]) - return dataset - - -def balance_dataset(dataset, npts): - - idx0 = np.argwhere(dataset.labels==0).flatten() - idx1 = np.argwhere(dataset.labels==1).flatten() - idx0 = idx0[:idx1.size] - idx = np.ravel(np.column_stack((idx0,idx1)))[:npts] - - dataset.npts = npts - dataset.features = dataset.features[idx] - dataset.labels = dataset.labels[idx] - return dataset - - -def divide_dataset(dataset, fraction=[0.8,0.2], shuffle=True): - """Divide the dataset in train and test dataset - - Args: - dataset (Daatclass): dataset - fraction (list, optional): how to divide train/test sets. Defaults to [0.8,0.2]. - shuffle (bool, optional): randomly change index of the dataset. Defaults to True. - - Returns: - tuple: train and test datasets - """ - index = np.arange(dataset.npts) - - if shuffle: - np.random.shuffle(index) - - n_train = int(fraction[0]*dataset.npts) - n_test = dataset.npts-n_train - idx_train = index[:n_train] - idx_test = index[n_train:] - train_dataset = DataSet(npts=n_train, features=dataset.features[idx_train,:], labels=dataset.labels[idx_train]) - test_dataset = DataSet(npts=n_test, features=dataset.features[idx_test,:], labels=dataset.labels[idx_test]) - - return train_dataset, test_dataset - -def extract_features(dataset, features): - dataset.features = dataset.features[:, features] - return dataset - -def get_normalization_data(dataset): - return dataset.features.min(0), dataset.features.max(0) - -def normalize(dataset, normalization_data): - dataset.features -= normalization_data[0] - dataset.features /= normalization_data[1] - return dataset \ No newline at end of file diff --git a/qalcore/pennylane/reupload.py b/qalcore/pennylane/reupload.py deleted file mode 100644 index 64b5e14..0000000 --- a/qalcore/pennylane/reupload.py +++ /dev/null @@ -1,243 +0,0 @@ -import pennylane as qml -from pennylane import numpy as np -from pennylane.optimize import AdamOptimizer, GradientDescentOptimizer -from .data import balance_dataset, extract_features, get_normalization_data, normalize -import matplotlib.pyplot as plt - - -@qml.qnode(qml.device("default.qubit", wires=1)) -def reupload_circuit(params, x, y): - """A variational quantum circuit representing the Universal classifier. - - Args: - params (array[float]): array of parameters - x (array[float]): single input vector - y (array[float]): single output state density matrix - - Returns: - float: fidelity between output state and input - """ - - n_inp_bloc = -(len(x)//-3) - - for p in params: - for i in range(n_inp_bloc): - qml.Rot(*x[i*3:(i+1)*3], wires=0) - qml.Rot(*p, wires=0) - return qml.expval(qml.Hermitian(y, wires=[0])) - -class ReuploadClassifier: - - def __init__(self, circuit, train_dataset, valid_dataset, num_layers ): - self.qcircuit = circuit - self.train_dataset = train_dataset - self.valid_dataset = valid_dataset - self.num_layers = num_layers - self.state_labels = np.array([[[1], [0]], [[0], [1]]], requires_grad=False) - - - def process_data(self, npts = 'all', features='all', normalization=True): - - if isinstance(npts, int): - self.train_dataset = balance_dataset(self.train_dataset, npts) - self.valid_dataset = balance_dataset(self.valid_dataset, npts) - - # only consider a subset of the features - if isinstance(features, list): - self.train_dataset = extract_features(self.train_dataset, features) - self.valid_dataset = extract_features(self.valid_dataset, features) - - # normalize the data between 0 and 2pi - if normalization: - normalization_data = get_normalization_data(self.train_dataset) - self.train_dataset = normalize(self.train_dataset, normalization_data) - self.valid_dataset = normalize(self.valid_dataset, normalization_data) - - # make int labels - self.train_dataset.labels = np.array(self.train_dataset.labels.astype(int), requires_grad=False) - self.train_dataset.features = np.array(self.train_dataset.features, requires_grad=False) - self.valid_dataset.labels = np.array(self.valid_dataset.labels.astype(int), requires_grad=False) - self.valid_dataset.features = np.array(self.valid_dataset.features, requires_grad=False) - - - # Define output labels as quantum state vectors - @staticmethod - def density_matrix(state): - """Calculates the density matrix representation of a state. - - Args: - state (array[complex]): array representing a quantum state vector - - Returns: - dm: (array[complex]): array representing the density matrix - """ - return state * np.conj(state).T - - def cost(self, params, x, y, state_labels=None): - """Cost function to be minimized. - - Args: - params (array[float]): array of parameters - x (array[float]): 2-d array of input vectors - y (array[float]): 1-d array of targets - state_labels (array[float]): array of state representations for labels - - Returns: - float: loss value to be minimized - """ - # Compute prediction for each input in data batch - loss = 0.0 - dm_labels = [self.density_matrix(s) for s in state_labels] - for i in range(len(x)): - f = self.qcircuit(params, x[i], dm_labels[y[i]]) - loss = loss + (1 - f) ** 2 - return loss / len(x) - - def test(self, params, x, y, state_labels=None): - """ - Tests on a given set of data. - - Args: - params (array[float]): array of parameters - x (array[float]): 2-d array of input vectors - y (array[float]): 1-d array of targets - state_labels (array[float]): 1-d array of state representations for labels - - Returns: - predicted (array([int]): predicted labels for test data - output_states (array[float]): output quantum states from the circuit - """ - fidelity_values = [] - dm_labels = [self.density_matrix(s) for s in state_labels] - predicted = [] - - for i in range(len(x)): - fidel_function = lambda y: self.qcircuit(params, x[i], y) - fidelities = [fidel_function(dm) for dm in dm_labels] - best_fidel = np.argmax(fidelities) - - predicted.append(best_fidel) - fidelity_values.append(fidelities) - - return np.array(predicted), np.array(fidelity_values) - - @staticmethod - def accuracy_score(y_true, y_pred): - """Accuracy score. - - Args: - y_true (array[float]): 1-d array of targets - y_predicted (array[float]): 1-d array of predictions - state_labels (array[float]): 1-d array of state representations for labels - - Returns: - score (float): the fraction of correctly classified samples - """ - score = y_true == y_pred - return score.sum() / len(y_true) - - @staticmethod - def iterate_minibatches(inputs, targets, batch_size): - """ - A generator for batches of the input data - - Args: - inputs (array[float]): input data - targets (array[float]): targets - - Returns: - inputs (array[float]): one batch of input data of length `batch_size` - targets (array[float]): one batch of targets of length `batch_size` - """ - for start_idx in range(0, inputs.shape[0] - batch_size + 1, batch_size): - idxs = slice(start_idx, start_idx + batch_size) - yield inputs[idxs], targets[idxs] - - @staticmethod - def pad_data(data): - if data.shape[1]%3 != 0: - nadd = 3-data.shape[1]%3 - data = np.hstack((data, np.zeros((data.shape[0], nadd), requires_grad=False))) - return data - - - def train(self, epochs = 25, batch_size = 32, opt = AdamOptimizer(0.6, beta1=0.9, beta2=0.999)): - - # Generate training and test data) - X_train = self.pad_data(self.train_dataset.features) - y_train = self.train_dataset.labels - - - X_test = self.pad_data(self.valid_dataset.features) - y_test = self.valid_dataset.labels - - # initialize random weights - params = np.random.uniform(size=(self.num_layers, 3), requires_grad=True) - - predicted_train, fidel_train = self.test(params, X_train, y_train, self.state_labels) - accuracy_train = self.accuracy_score(y_train, predicted_train) - - predicted_test, fidel_test = self.test(params, X_test, y_test, self.state_labels) - accuracy_test = self.accuracy_score(y_test, predicted_test) - - # save predictions with random weights for comparison - initial_predictions = predicted_test - loss = self.cost(params, X_test, y_test, self.state_labels) - - print( - "Epoch: {:2d} | Cost: {:3f} | Train accuracy: {:3f} | Test Accuracy: {:3f}".format( - 0, loss, accuracy_train, accuracy_test - ) - ) - - for it in range(epochs): - for Xbatch, ybatch in self.iterate_minibatches(X_train, y_train, batch_size=batch_size): - params, _, _, _ = opt.step(self.cost, params, Xbatch, ybatch, self.state_labels) - - predicted_train, fidel_train = self.test(params, X_train, y_train, self.state_labels) - accuracy_train = self.accuracy_score(y_train, predicted_train) - loss = self.cost(params, X_train, y_train, self.state_labels) - - predicted_test, fidel_test = self.test(params, X_test, y_test, self.state_labels) - accuracy_test = self.accuracy_score(y_test, predicted_test) - res = [it + 1, loss, accuracy_train, accuracy_test] - print( - "Epoch: {:2d} | Loss: {:3f} | Train accuracy: {:3f} | Test accuracy: {:3f}".format( - *res - ) - ) - - - print("Learned weights") - for i in range(self.num_layers): - print("Layer {}: {}".format(i, params[i])) - - fig, axes = plt.subplots(1, 3, figsize=(10, 3)) - self.plot_data(X_test, initial_predictions, fig, axes[0]) - self.plot_data(X_test, predicted_test, fig, axes[1]) - self.plot_data(X_test, y_test, fig, axes[2]) - axes[0].set_title("Predictions with random weights") - axes[1].set_title("Predictions after training") - axes[2].set_title("True test data") - plt.tight_layout() - plt.show() - - return params - - @staticmethod - def plot_data(x, y, fig=None, ax=None): - """ - Plot data with red/blue values for a binary classification. - - Args: - x (array[tuple]): array of data points as tuples - y (array[int]): array of data points as tuples - """ - if fig == None: - fig, ax = plt.subplots(1, 1, figsize=(5, 5)) - reds = y == 0 - blues = y == 1 - ax.scatter(x[reds, 0], x[reds, 1], c="red", s=20, edgecolor="k", alpha=0.1) - ax.scatter(x[blues, 0], x[blues, 1], c="blue", s=20, edgecolor="k", alpha=0.1) - ax.set_xlabel("$x_1$") - ax.set_ylabel("$x_2$") \ No newline at end of file diff --git a/qalcore/qiskit/__init__.py b/qalcore/qiskit/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qalcore/qiskit/vqfd/__init__.py b/qalcore/qiskit/vqfd/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/qalcore/qiskit/vqfd/numpy_fd_solver.py b/qalcore/qiskit/vqfd/numpy_fd_solver.py deleted file mode 100644 index ead45ba..0000000 --- a/qalcore/qiskit/vqfd/numpy_fd_solver.py +++ /dev/null @@ -1,13 +0,0 @@ -''' -Solving finite difference problems using numpy -''' - - -class NumPyFDSolver(): - - def __init__(self): - pass - -class NumPyPoissonSolver(): - def __init__(self): - pass \ No newline at end of file diff --git a/qalcore/qiskit/vqfd/utils.py b/qalcore/qiskit/vqfd/utils.py deleted file mode 100644 index d0f1992..0000000 --- a/qalcore/qiskit/vqfd/utils.py +++ /dev/null @@ -1,55 +0,0 @@ -"""Prepare the state -|0>|A> + |1>|B>.""" - -from curses import meta -from typing import Optional, List, Union, Dict, Sequence -from qiskit import QuantumCircuit, QuantumRegister -from qiskit.circuit.parameterexpression import ParameterValueType -from qiskit.circuit.register import Register -from qiskit.circuit.bit import Bit - -class HadamardCircuitSuperposition(QuantumCircuit): - - def __init__( - self, - num_qubit: int, - circuit_A: QuantumCircuit, - circuit_B: QuantumCircuit, - name: Optional[str] = None, - global_phase: ParameterValueType = 0, - metadata: Optional[Dict] = None, - ): - - super().__init__(num_qubit) - - self.h(0) - self.compose(circuit_A.control(1), qubits=list(range(0, self.num_qubits)), inplace=True) - self.x(0) - self.compose(circuit_B.control(1), qubits=list(range(0, self.num_qubits)), inplace=True) - - -class ShiftOperator(QuantumCircuit): - - def __init__( - self, - regs: Union[Register, int, Sequence[Bit]], - name: Optional[str] = None, - global_phase: ParameterValueType = 0, - metadata: Optional[Dict] = None, - use_mct_ancilla: bool = False - ): - - self.qreg = QuantumRegister(regs) - super().__init__(self.qreg) - - - if not use_mct_ancilla: - for i in reversed(range(1, self.num_qubits)): - self.mct(self.qreg[:i], self.qreg[i]) - self.x(self.qreg[0]) - else: - qreg_shift_ancilla = QuantumRegister(self.num_qubits-3, 'q_shift_ancilla') - self.add_register(qreg_shift_ancilla) - for i in reversed(range(1, self.num_qubits)): - self.mct(self.qreg[:i], self.qreg[i], qreg_shift_ancilla, mode='v-chain') - self.x(self.qreg[0]) \ No newline at end of file diff --git a/qalcore/qiskit/vqfd/variational_fd_solver.py b/qalcore/qiskit/vqfd/variational_fd_solver.py deleted file mode 100644 index f9d820d..0000000 --- a/qalcore/qiskit/vqfd/variational_fd_solver.py +++ /dev/null @@ -1,103 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2020, 2021. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""An abstract class for variational linear systems solvers.""" - -from abc import ABC, abstractmethod -from typing import Union, Optional, List, Callable -import numpy as np - -from qiskit import QuantumCircuit - -from qiskit.quantum_info.operators.base_operator import BaseOperator - -from qiskit.algorithms.linear_solvers.observables.linear_system_observable import ( - LinearSystemObservable, -) -from qiskit.algorithms.variational_algorithm import VariationalResult -from qiskit.algorithms.linear_solvers.linear_solver import LinearSolverResult - - -class VariationalFDSolverResult(LinearSolverResult, VariationalResult): - """A base class for linear systems results using variational methods - - The linear systems variational algorithms return an object of the type ``VariationalLinearSystemsResult`` - with the information about the solution obtained. - """ - - def __init__(self) -> None: - super().__init__() - - @property - def cost_function_evals(self) -> Optional[int]: - """Returns number of cost optimizer evaluations""" - return self._cost_function_evals - - @cost_function_evals.setter - def cost_function_evals(self, value: int) -> None: - """Sets number of cost function evaluations""" - self._cost_function_evals = value - - @property - def state(self) -> Union[QuantumCircuit, np.ndarray]: - """return either the circuit that prepares the solution or the solution as a vector""" - return self._state - - @state.setter - def state(self, state: Union[QuantumCircuit, np.ndarray]) -> None: - """Set the solution state as either the circuit that prepares it or as a vector. - - Args: - state: The new solution state. - """ - self._state = state - - -class VariationalFDSolver(ABC): - """An abstract class for linear system solvers in Qiskit.""" - - @abstractmethod - def solve( - self, - matrix: Union[np.ndarray, QuantumCircuit], - vector: Union[np.ndarray, QuantumCircuit], - observable: Optional[ - Union[ - LinearSystemObservable, - BaseOperator, - List[LinearSystemObservable], - List[BaseOperator], - ] - ] = None, - observable_circuit: Optional[ - Union[QuantumCircuit, List[QuantumCircuit]] - ] = None, - post_processing: Optional[ - Callable[[Union[float, List[float]]], Union[float, List[float]]] - ] = None, - ) -> VariationalFDSolverResult: - """Solve the system and compute the observable(s) - - Args: - matrix: The matrix specifying the system, i.e. A in Ax=b. - vector: The vector specifying the right hand side of the equation in Ax=b. - observable: Optional information to be extracted from the solution. - Default is the probability of success of the algorithm. - observable_circuit: Optional circuit to be applied to the solution to extract - information. Default is ``None``. - post_processing: Optional function to compute the value of the observable. - Default is the raw value of measuring the observable. - - Returns: - The result of the linear system. - """ - raise NotImplementedError diff --git a/qalcore/qiskit/vqfd/vqap.py b/qalcore/qiskit/vqfd/vqap.py deleted file mode 100644 index c8bc73e..0000000 --- a/qalcore/qiskit/vqfd/vqap.py +++ /dev/null @@ -1,758 +0,0 @@ -# VariationalVariational Quantum Algorithm based on the minimum potential energy for solving the Poisson equation -# Ref : -# Tutorial : - - -"""Variational Quantum Algorithm based on the minimum potential energy -for solving the Poisson equation -Original code : https://github/com/ToyotaCRDL/VQAPoisson -See https://arxiv.org/abs/2106.09333 -""" - - -from typing import Optional, Union, List, Callable, Tuple -import numpy as np -from qiskit.circuit.library.n_local.real_amplitudes import RealAmplitudes -from qiskit import Aer -from qiskit import QuantumCircuit -from qiskit.circuit import Parameter -from qiskit.algorithms.variational_algorithm import VariationalAlgorithm -from qiskit.providers import Backend -from qiskit.quantum_info.operators import Operator -from qiskit.quantum_info.operators.base_operator import BaseOperator -from qiskit.utils import QuantumInstance -from qiskit.utils.backend_utils import is_aer_provider, is_statevector_backend -from qiskit.utils.validation import validate_min - -from qiskit.algorithms.linear_solvers.observables.linear_system_observable import ( - LinearSystemObservable, -) - -from qiskit.algorithms.minimum_eigen_solvers.vqe import ( - _validate_bounds, - _validate_initial_point, -) - - -from qiskit.opflow import ( - Z, - X, - I, - StateFn, - OperatorBase, - TensoredOp, - ExpectationBase, - CircuitSampler, - ListOp, - ExpectationFactory, -) - -from qiskit.algorithms.optimizers import SLSQP, Minimizer, Optimizer -from qiskit.opflow.gradients import GradientBase -from qalcore.qiskit.vqls.variational_linear_solver import ( - VariationalLinearSolver, - VariationalLinearSolverResult, -) -from qalcore.qiskit.vqfd.utils import ShiftOperator, HadamardCircuitSuperposition - - -class VQAP(VariationalAlgorithm, VariationalLinearSolver): - - r"""Systems of linear equations arise naturally in many real-life applications in a wide range - of areas, such as in the solution of Partial Differential Equations, the calibration of - financial models, fluid simulation or numerical field calculation. The problem can be defined - as, given a matrix :math:`A\in\mathbb{C}^{N\times N}` and a vector - :math:`\vec{b}\in\mathbb{C}^{N}`, find :math:`\vec{x}\in\mathbb{C}^{N}` satisfying - :math:`A\vec{x}=\vec{b}`. - - Examples: - - .. jupyter-execute: - - from qalcore.qiskit.vqfd.vqap import VQAP - from qiskit.circuit.library.n_local.real_amplitudes import RealAmplitudes - from qiskit.algorithms.optimizers import COBYLA - from qiskit.algorithms.linear_solvers.numpy_linear_solver import NumPyLinearSolver - from qiskit import Aer - import numpy as np - - # define the matrix and the rhs - matrix = np.random.rand(4,4) - matrix = (matrix + matrix.T) - rhs = np.random.rand(4) - - # number of qubits needed - num_qubits = int(log2(A.shape[0])) - - # get the classical solution - classical_solution = NumPyLinearSolver().solve(matrix,rhs/np.linalg.norm(rhs)) - - # specify the backend - backend = Aer.get_backend('aer_simulator_statevector') - - # specify the ansatz - ansatz = RealAmplitudes(num_qubits, entanglement='full', reps=3, insert_barriers=False) - - # declare the solver - vqls = VQLS( - ansatz=ansatz, - optimizer=COBYLA(maxiter=200, disp=True), - quantum_instance=backend - ) - - # solve the system - solution = vqls.solve(matrix,rhs) - - References: - - [1] Yuki Sato et al. - Variational Quantum Algorithm based on the minimum potential energy for solving the Poisson equation - `arXiv:2106.09333 ` - """ - - def __init__( - self, - ansatz: Optional[QuantumCircuit] = None, - boundary: Optional[str] = None, - optimizer: Optional[Union[Optimizer, Minimizer]] = None, - initial_point: Optional[np.ndarray] = None, - gradient: Optional[Union[GradientBase, Callable]] = None, - expectation: Optional[ExpectationBase] = None, - include_custom: bool = False, - max_evals_grouped: int = 1, - callback: Optional[Callable[[int, np.ndarray, float, float], None]] = None, - quantum_instance: Optional[Union[Backend, QuantumInstance]] = None, - ) -> None: - r""" - Args: - ansatz: A parameterized circuit used as Ansatz for the wave function. - optimizer: A classical optimizer. Can either be a Qiskit optimizer or a callable - that takes an array as input and returns a Qiskit or SciPy optimization result. - initial_point: An optional initial point (i.e. initial parameter values) - for the optimizer. If ``None`` then VQE will look to the ansatz for a preferred - point and if not will simply compute a random one. - gradient: An optional gradient function or operator for optimizer. - expectation: The Expectation converter for taking the average value of the - Observable over the ansatz state function. When ``None`` (the default) an - :class:`~qiskit.opflow.expectations.ExpectationFactory` is used to select - an appropriate expectation based on the operator and backend. When using Aer - qasm_simulator backend, with paulis, it is however much faster to leverage custom - Aer function for the computation but, although VQE performs much faster - with it, the outcome is ideal, with no shot noise, like using a state vector - simulator. If you are just looking for the quickest performance when choosing Aer - qasm_simulator and the lack of shot noise is not an issue then set `include_custom` - parameter here to ``True`` (defaults to ``False``). - include_custom: When `expectation` parameter here is None setting this to ``True`` will - allow the factory to include the custom Aer pauli expectation. - max_evals_grouped: Max number of evaluations performed simultaneously. Signals the - given optimizer that more than one set of parameters can be supplied so that - potentially the expectation values can be computed in parallel. Typically this is - possible when a finite difference gradient is used by the optimizer such that - multiple points to compute the gradient can be passed and if computed in parallel - improve overall execution time. Deprecated if a gradient operator or function is - given. - callback: a callback that can access the intermediate data during the optimization. - Three parameter values are passed to the callback as follows during each evaluation - by the optimizer for its current set of parameters as it works towards the minimum. - These are: the evaluation count, the cost and the optimizer parameters for the ansatz - quantum_instance: Quantum Instance or Backend - """ - super().__init__() - - - self._num_qubits = None - - self._initial_point = None - self.initial_point = initial_point - self._max_evals_grouped = max_evals_grouped - - self._ansatz = None - self.ansatz = ansatz - - self._boundary = None - self.boundary = boundary - - self._optimizer = None - self.optimizer = optimizer - - self._gradient = None - self.gradient = gradient - - - self._quantum_instance = None - - if quantum_instance is None: - quantum_instance = Aer.get_backend("aer_simulator_statevector") - self.quantum_instance = quantum_instance - - self._callback = None - self.callback = callback - - tol = 1E-3 - self.tol = { - 'Periodic': tol, - 'Neumann': tol, - 'Dirichlet': 0.0 - }[self.boundary] - - self.observables = None - self.source_circuit = None - self.shifted_ansatz = None - - @property - def num_qubits(self) -> int: - """return the numner of qubits""" - return self._num_qubits - - @num_qubits.setter - def num_qubits(self, num_qubits: int) -> None: - """Set the number of qubits""" - self._num_qubits = num_qubits - - @property - def num_clbits(self) -> int: - """return the numner of classical bits""" - return self._num_clbits - - @num_clbits.setter - def num_clbits(self, num_clbits: int) -> None: - """Set the number of classical bits""" - self._num_clbits = num_clbits - - @property - def ansatz(self) -> QuantumCircuit: - """Returns the ansatz.""" - return self._ansatz - - @ansatz.setter - def ansatz(self, ansatz: Optional[QuantumCircuit]): - """Sets the ansatz. - - Args: - ansatz: The parameterized circuit used as an ansatz. - If None is passed, RealAmplitudes is used by default. - - """ - if ansatz is None: - ansatz = RealAmplitudes() - - self._ansatz = ansatz - self.num_qubits = ansatz.num_qubits - - @property - def boundary(self) -> str: - """getter for boundary prop - - Returns: - str: value of boundary - """ - return self._boundary - - @boundary.setter - def boundary(self, boundary: Optional[str]): - """Setter for boundary prop - - Args: - boundary (Optional[str]): desired boundary - - Raises: - ValueError: id not recognized - """ - if boundary is None: - boundary = 'Dirichlet' - self._boundary = boundary - if self.boundary not in ['Neumann', 'Dirichlet', 'Periodic']: - raise ValueError('boundary must be Neumann, Dirichlet or Periodic not %s' %self.boundary) - - - @property - def quantum_instance(self) -> Optional[QuantumInstance]: - """Returns quantum instance.""" - return self._quantum_instance - - @quantum_instance.setter - def quantum_instance( - self, quantum_instance: Union[QuantumInstance, Backend] - ) -> None: - """Sets quantum_instance""" - if not isinstance(quantum_instance, QuantumInstance): - quantum_instance = QuantumInstance(quantum_instance) - - self._quantum_instance = quantum_instance - self._circuit_sampler = CircuitSampler( - quantum_instance, - statevector=is_statevector_backend(quantum_instance.backend), - param_qobj=is_aer_provider(quantum_instance.backend), - ) - - @property - def initial_point(self) -> Optional[np.ndarray]: - """Returns initial point""" - return self._initial_point - - @initial_point.setter - def initial_point(self, initial_point: np.ndarray): - """Sets initial point""" - self._initial_point = initial_point - - @property - def max_evals_grouped(self) -> int: - """Returns max_evals_grouped""" - return self._max_evals_grouped - - @max_evals_grouped.setter - def max_evals_grouped(self, max_evals_grouped: int): - """Sets max_evals_grouped""" - self._max_evals_grouped = max_evals_grouped - self.optimizer.set_max_evals_grouped(max_evals_grouped) - - @property - def callback(self) -> Optional[Callable[[int, np.ndarray, float, float], None]]: - """Returns callback""" - return self._callback - - @callback.setter - def callback( - self, callback: Optional[Callable[[int, np.ndarray, float, float], None]] - ): - """Sets callback""" - self._callback = callback - - - @property - def optimizer(self) -> Optimizer: - """Returns optimizer""" - return self._optimizer - - @optimizer.setter - def optimizer(self, optimizer: Optional[Optimizer]): - """Sets the optimizer attribute. - - Args: - optimizer: The optimizer to be used. If None is passed, SLSQP is used by default. - - """ - if optimizer is None: - optimizer = SLSQP() - - if isinstance(optimizer, Optimizer): - optimizer.set_max_evals_grouped(self.max_evals_grouped) - - self._optimizer = optimizer - - def construct_source_circuit(self, source: Union[np.ndarray, QuantumCircuit] ) -> None: - """Constructs the different circuits needed to compute the loss function - - Args: - source (Union[np.ndarray, QuantumCircuit]): the source term of the poisson equation - """ - - # state preparation - if isinstance(source, QuantumCircuit): - nb = source.num_qubits - self.source_circuit = source - - elif isinstance(source, np.ndarray): - - # ensure the vector is double - source = source.astype("float64") - - # create the circuit - nb = int(np.log2(len(source))) - self.source_circuit = QuantumCircuit(nb) - - # prep the vector if its norm is non nul - vec_norm = np.linalg.norm(source) - if vec_norm != 0: - self.source_circuit.prepare_state(source / vec_norm) - - def construct_observable(self) -> None: - """Constructs all the observable required for the evaluation of the cost function - """ - - # create the obsevable - zero_op = (I + Z) / 2 - one_op = (I - Z) / 2 - self.observables = { - "I^(n-1)X" : TensoredOp((self.num_qubits-1) * [I] ) ^ X, - "Io^(n-1)X": TensoredOp((self.num_qubits-1) * [zero_op] ) ^ X, - "Io^(n-1)I": TensoredOp((self.num_qubits-1) * [zero_op] ) ^ I, - "I^(n)O": TensoredOp((self.num_qubits) * [I]) ^ one_op, - "XI^(n)": X ^ TensoredOp((self.num_qubits) * [I]) - } - - def construct_expectation( - self, - parameter: Union[List[float], List[Parameter], np.ndarray], - circuit: QuantumCircuit, - observable: OperatorBase, - ) -> Union[OperatorBase, Tuple[OperatorBase, ExpectationBase]]: - r""" - Generate the ansatz circuit and expectation value measurement, and return their - runnable composition. - - Args: - parameter: Parameters for the ansatz circuit. - circuit: one of the circuit required for the cost calculation - - Returns: - The Operator equalling the measurement of the circuit :class:`StateFn` by the - observable's expectation :class:`StateFn` - - """ - - # assign param to circuit - wave_function = circuit.assign_parameters(parameter) - - # compose the statefn of the observable on the circuit - return ~StateFn(observable) @ StateFn(wave_function) - - def get_matrix(self): - """Returns the finite difference matrix - """ - - if self.observables is None: - self.construct_observable() - - S = np.real(Operator(ShiftOperator(self.num_qubits)).data) - - H1 = np.real(Operator(self.observables["I^(n-1)X"]).data) - H2 = S.T @ H1 @ S - H3 = S.T @ (np.real(Operator(self.observables["Io^(n-1)X"]).data)) @ S - H4 = S.T @ (np.real(Operator(self.observables["Io^(n-1)I"]).data)) @ S - - size = 2**self.num_qubits - A = 2*np.eye(size) - H1 - H2 - - if self.boundary == 'Dirichlet': - A += H3 - - if self.boundary == 'Neumann': - A += H3 - H4 - - return A - - def construct_shift_ansatz(self): - """return a circuits that compose the ansatz and the shift operator - """ - self.shifted_ansatz = self.ansatz.compose(ShiftOperator(self.num_qubits)) - - def assemble_circuits(self): - """Creates a list of circuits/observable/weight required for the calculation - of the cost function - - Returns: - Tuple(): circuits, observables, weights - """ - - if self.shifted_ansatz is None: - self.construct_shift_ansatz() - - circuits, observables = [], [] - - # circuits for the numerator - circuits += [ - HadamardCircuitSuperposition( - self.num_qubits+1, - self.source_circuit, - self.ansatz - ) - ] - # observable for the numerator - observables += [ - self.observables["XI^(n)"] - ] - - # circuits for denominator - circuits += [ - self.ansatz, - self.shifted_ansatz, - ] - - # observable for the denominator - if self.boundary == 'Periodic': - observables += [ - - self.observables["I^(n-1)X"], - - self.observables["I^(n-1)X"] - ] - - elif self.boundary == 'Dirichlet': - observables += [ - - self.observables["I^(n-1)X"], - - self.observables["I^(n-1)X"] + self.observables["Io^(n-1)X"] - ] - - elif self.boundary == 'Neumann': - observables += [ - - self.observables["I^(n-1)X"], - self.observables["I^(n-1)X"] + self.observables["Io^(n-1)X"] - - self.observables["Io^(n-1)I"] - ] - - - return circuits, observables - - def process_probability_circuit_output( - self, - probability_circuit_output: List, - return_norm: bool = False - ) -> float: - """Compute the final cost function from the sampled circuit values - - Args: - probability_circuit_output (List): _description_ - weights (List): _description_ - - Returns: - float: _description_ - """ - if return_norm: - numerator = probability_circuit_output[0] - else: - numerator = -0.5*probability_circuit_output[0]**2 - - denominator = 2.0 + probability_circuit_output[1] + probability_circuit_output[2] - return numerator/denominator + self.tol - - - def get_norm_solution(self) -> float: - """Compute the norm of the solution - - Returns: - float: _description_ - """ - - num_parameters = self.ansatz.num_parameters - if num_parameters == 0: - raise RuntimeError( - "The ansatz must be parameterized, but has 0 free parameters." - ) - circuits, observables = self.assemble_circuits() - ansatz_params = self.ansatz.parameters - expect_ops = [] - for circ, obs in zip(circuits, observables): - expect_ops.append(self.construct_expectation(ansatz_params, circ, obs)) - - expect_ops = ListOp(expect_ops) - - # Create dict associating each parameter with the lists of parameterization values for it - parameter_sets = np.reshape(ansatz_params, (-1, num_parameters)) - param_bindings = dict( - zip(ansatz_params, parameter_sets.transpose().tolist()) - ) - - # TODO define a multiple sampler, one for each ops, to leverage caching - # get the sampled output - out = [] - for op in expect_ops: - sampled_expect_op = self._circuit_sampler.convert( - op, params=param_bindings) - out.append(sampled_expect_op.eval()[0]) - - # compute the total cost - return self.process_probability_circuit_output(out, return_norm=True) - - - def get_cost_evaluation_function( - self, - ) -> Callable[[np.ndarray], Union[float, List[float]]]: - """Generate the cost function of the minimazation process - - Args: - circuits (List[QuantumCircuit]): circuits necessary to compute the cost function - - Raises: - RuntimeError: If the ansatz is not parametrizable - - Returns: - Callable[[np.ndarray], Union[float, List[float]]]: the cost function - """ - - num_parameters = self.ansatz.num_parameters - if num_parameters == 0: - raise RuntimeError( - "The ansatz must be parameterized, but has 0 free parameters." - ) - circuits, observables = self.assemble_circuits() - ansatz_params = self.ansatz.parameters - expect_ops = [] - for circ, obs in zip(circuits, observables): - expect_ops.append(self.construct_expectation(ansatz_params, circ, obs)) - - expect_ops = ListOp(expect_ops) - - def cost_evaluation(parameters): - - # Create dict associating each parameter with the lists of parameterization values for it - parameter_sets = np.reshape(parameters, (-1, num_parameters)) - param_bindings = dict( - zip(ansatz_params, parameter_sets.transpose().tolist()) - ) - - # TODO define a multiple sampler, one for each ops, to leverage caching - # get the sampled output - out = [] - for op in expect_ops: - sampled_expect_op = self._circuit_sampler.convert( - op, params=param_bindings - ) - out.append(sampled_expect_op.eval()[0]) - - # compute the total cost - cost = self.process_probability_circuit_output(out) - - # get the internediate results if required - if self._callback is not None: - for param_set in parameter_sets: - self._eval_count += 1 - self._callback(self._eval_count, cost, param_set) - else: - self._eval_count += 1 - - return cost - - return cost_evaluation - - def _calculate_observable( - self, - solution: QuantumCircuit, - observable: Optional[Union[LinearSystemObservable, BaseOperator]] = None, - observable_circuit: Optional[QuantumCircuit] = None, - post_processing: Optional[ - Callable[[Union[float, List[float]]], Union[float, List[float]]] - ] = None, - ) -> Tuple[Union[float, List[float]], Union[float, List[float]]]: - """Calculates the value of the observable(s) given. - - Args: - solution: The quantum circuit preparing the solution x to the system. - observable: Information to be extracted from the solution. - observable_circuit: Circuit to be applied to the solution to extract information. - post_processing: Function to compute the value of the observable. - - Returns: - The value of the observable(s) and the circuit results before post-processing as a - tuple. - """ - # exit if nothing is provided - if observable is None and observable_circuit is None: - return None, None - - # Get the number of qubits - nb = solution.num_qubits - - # if the observable is given construct post_processing and observable_circuit - if observable is not None: - observable_circuit = observable.observable_circuit(nb) - post_processing = observable.post_processing - - if isinstance(observable, LinearSystemObservable): - observable = observable.observable(nb) - - is_list = True - if not isinstance(observable_circuit, list): - is_list = False - observable_circuit = [observable_circuit] - observable = [observable] - - expectations = [] - for circ, obs in zip(observable_circuit, observable): - circuit = QuantumCircuit(solution.num_qubits) - circuit.append(solution, circuit.qubits) - circuit.append(circ, range(nb)) - expectations.append(~StateFn(obs) @ StateFn(circuit)) - - if is_list: - # execute all in a list op to send circuits in batches - expectations = ListOp(expectations) - else: - expectations = expectations[0] - - # check if an expectation converter is given - if self._expectation is not None: - expectations = self._expectation.convert(expectations) - # if otherwise a backend was specified, try to set the best expectation value - elif self._circuit_sampler is not None: - if is_list: - op = expectations.oplist[0] - else: - op = expectations - self._expectation = ExpectationFactory.build( - op, self._circuit_sampler.quantum_instance - ) - - if self._circuit_sampler is not None: - expectations = self._circuit_sampler.convert(expectations) - - # evaluate - expectation_results = expectations.eval() - - # apply post_processing - result = post_processing(expectation_results, nb) - - return result, expectation_results - - def solve( - self, - source: Union[np.ndarray, QuantumCircuit], - observable: Optional[ - Union[ - LinearSystemObservable, - BaseOperator, - List[LinearSystemObservable], - List[BaseOperator], - ] - ] = None, - observable_circuit: Optional[ - Union[QuantumCircuit, List[QuantumCircuit]] - ] = None, - post_processing: Optional[ - Callable[[Union[float, List[float]]], Union[float, List[float]]] - ] = None, - ) -> VariationalLinearSolverResult: - - - self.construct_source_circuit(source) - self.construct_observable() - self.construct_shift_ansatz() - - # set an expectation for this algorithm run (will be reset to None at the end) - initial_point = _validate_initial_point(self.initial_point, self.ansatz) - bounds = _validate_bounds(self.ansatz) - - # Convert the gradient operator into a callable function that is compatible with the - # optimization routine. - gradient = self._gradient - - self._eval_count = 0 - - # get the cost evaluation function - cost_evaluation = self.get_cost_evaluation_function() - - if callable(self.optimizer): - opt_result = self.optimizer( # pylint: disable=not-callable - fun=cost_evaluation, x0=initial_point, jac=gradient, bounds=bounds - ) - else: - opt_result = self.optimizer.minimize( - fun=cost_evaluation, x0=initial_point, jac=gradient, bounds=bounds - ) - - # create the solution - solution = VariationalLinearSolverResult() - - # optimization data - solution.optimal_point = opt_result.x - solution.optimal_parameters = dict(zip(self.ansatz.parameters, opt_result.x)) - solution.optimal_value = opt_result.fun - solution.cost_function_evals = opt_result.nfev - - # final ansatz - solution.state = self.ansatz.assign_parameters(solution.optimal_parameters) - - # observable - solution.observable = self._calculate_observable( - solution.state, observable, observable_circuit, post_processing - ) - - return solution \ No newline at end of file diff --git a/qalcore/qiskit/vqfd/vqees.py b/qalcore/qiskit/vqfd/vqees.py deleted file mode 100644 index 42d5bde..0000000 --- a/qalcore/qiskit/vqfd/vqees.py +++ /dev/null @@ -1,67 +0,0 @@ -from qalcore.qiskit.vqls.variational_linear_solver import VariationalLinearSolver, VariationalLinearSolverResult -from qalcore.qiskit.vqfd.vqap import VQAP -import numpy as np -from qiskit.quantum_info import Statevector -from typing import List - -class VQAP_IE(VQAP): - - def __init__(self, delta_x, *args, **kwargs): - super().__init__(*args, **kwargs) - self.delta_x = delta_x - - def process_probability_circuit_output( - self, - probability_circuit_output: List, - return_norm: bool = False - ) -> float: - """Compute the final cost function from the sampled circuit values - - Args: - probability_circuit_output (List): _description_ - weights (List): _description_ - - Returns: - float: _description_ - """ - if return_norm: - numerator = probability_circuit_output[0] - else: - numerator = -0.5*probability_circuit_output[0]**2 - - denominator = 3.0 + self.delta_x*(probability_circuit_output[1] + probability_circuit_output[2]) - return numerator/denominator + self.tol - -class VQEES(): - - def __init__(self, solver: VQAP): - self.solver = solver - self.num_qubits = solver.num_qubits - - def process_solution(self, res): - vqap_solution = np.real(Statevector(res.state).data) - return vqap_solution - - - def solve(self, initial_condition: np.ndarray, - tmax: float, dt: float, t0: float = 0.0): - - solution = [] - solution.append(initial_condition) - time = np.arange(t0,tmax,dt) - nt = len(time) - - for i in range(nt): - - # prepare the rhs - source = solution[i] - source /= np.linalg.norm(source) - - # solve the linear system - sol = self.process_solution(self.solver.solve(source)) - - # store the solution - norm = np.linalg.norm(sol) - solution.append(norm*sol) - - return solution \ No newline at end of file diff --git a/qalcore/qiskit/vqls/__init__.py b/qalcore/qiskit/vqls/__init__.py deleted file mode 100644 index f1d9c47..0000000 --- a/qalcore/qiskit/vqls/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2022. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -""" -======================================= -Variational Quantum Linear Solver -======================================= -""" - -# The code of the vqls has been moved to: https://github.com/QuantumApplicationLab/vqls-prototype -# and has been made available through the qiskit ecosystem : https://qiskit.org/ecosystem/ - -from vqls_prototype.solver.vqls import VQLS -from vqls_prototype.solver.qst_vqls import QST_VQLS -from vqls_prototype.solver.hybrid_qst_vqls import Hybrid_QST_VQLS - - -__all__ = [ - "VQLS", - "QST_VQLS", - "Hybrid_QST_VQLS" -] diff --git a/qalcore/qubols/__init__.py b/qalcore/qubols/__init__.py new file mode 100644 index 0000000..de7f990 --- /dev/null +++ b/qalcore/qubols/__init__.py @@ -0,0 +1,25 @@ +""" +======================================= +Variational Quantum Linear Solver +======================================= +""" + +# The code of the vqls has been moved to: https://github.com/QuantumApplicationLab/qubols + + +from qubols.qubols import QUBOLS +from qubols.encodings import ( + EfficientEncoding, + RealQbitEncoding, + RealUnitQbitEncoding, + PositiveQbitEncoding, +) + + +__all__ = [ + "QUBOLS", + "EfficientEncoding", + "RealQbitEncoding", + "RealUnitQbitEncoding", + "PositiveQbitEncoding", +] diff --git a/qalcore/vqls_prototype/__init__.py b/qalcore/vqls_prototype/__init__.py new file mode 100644 index 0000000..945fd67 --- /dev/null +++ b/qalcore/vqls_prototype/__init__.py @@ -0,0 +1,15 @@ +""" +======================================= +Variational Quantum Linear Solver +======================================= +""" + +# The code of the vqls has been moved to: https://github.com/QuantumApplicationLab/vqls-prototype +# and has been made available through the qiskit ecosystem : https://qiskit.org/ecosystem/ + +from vqls_prototype.solver.vqls import VQLS +from vqls_prototype.solver.qst_vqls import QST_VQLS +from vqls_prototype.solver.hybrid_qst_vqls import Hybrid_QST_VQLS + + +__all__ = ["VQLS", "QST_VQLS", "Hybrid_QST_VQLS"] diff --git a/setup.cfg b/setup.cfg index c35eb35..97eb519 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,17 +33,7 @@ zip_safe = False include_package_data = True packages = find: install_requires = - numpy - scipy - qiskit - qiskit_algorithms - qiskit-ibm-runtime - matplotlib - jupyter - pylatexenc - sympy - dwave-ocean-sdk - mthree + qubols @ git+https://github.com/QuantumApplicationLab/qubols vqls-prototype @ git+https://github.com/QuantumApplicationLab/vqls-prototype diff --git a/tests/qiskit/vqls/test_vqls.py b/tests/qiskit/vqls/test_vqls.py index 149ae58..b45c160 100644 --- a/tests/qiskit/vqls/test_vqls.py +++ b/tests/qiskit/vqls/test_vqls.py @@ -23,7 +23,7 @@ from qiskit_algorithms.optimizers import ADAM from qiskit.primitives import Estimator, Sampler, BackendEstimator, BackendSampler -from vqls_prototype import VQLS +from qalcore.vqls_prototype import VQLS # 8-11-2023 # Overlap Hadamard test do not work with BasicAer primitives anymore From 7a4db53b67f90ea2d4e87dfed629b5f06972eb18 Mon Sep 17 00:00:00 2001 From: Nicolas Renaud Date: Wed, 14 Feb 2024 16:42:52 +0100 Subject: [PATCH 2/3] remove test --- tests/qiskit/vqls/test_vqls.py | 122 --------------------------------- 1 file changed, 122 deletions(-) delete mode 100644 tests/qiskit/vqls/test_vqls.py diff --git a/tests/qiskit/vqls/test_vqls.py b/tests/qiskit/vqls/test_vqls.py deleted file mode 100644 index b45c160..0000000 --- a/tests/qiskit/vqls/test_vqls.py +++ /dev/null @@ -1,122 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2018, 2021. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -""" Test VQLS """ - - -import unittest -from qiskit.test import QiskitTestCase - -import numpy as np - -from qiskit import BasicAer, QuantumCircuit -from qiskit.circuit.library import RealAmplitudes - -from qiskit_algorithms.optimizers import ADAM -from qiskit.primitives import Estimator, Sampler, BackendEstimator, BackendSampler -from qalcore.vqls_prototype import VQLS - -# 8-11-2023 -# Overlap Hadamard test do not work with BasicAer primitives anymore -# this test case is skipped for now - - -class TestVQLS(QiskitTestCase): - """Test VQLS""" - - def setUp(self): - super().setUp() - - self.options = ( - {"use_local_cost_function": False, "use_overlap_test": False}, - {"use_local_cost_function": True, "use_overlap_test": False}, - {"use_local_cost_function": False, "use_overlap_test": True}, - ) - - self.estimators = ( - Estimator(), - BackendEstimator(BasicAer.get_backend("qasm_simulator")), - ) - - self.samplers = ( - Sampler(), - BackendSampler(BasicAer.get_backend("qasm_simulator")), - ) - - def test_numpy_input(self): - """Test the VQLS on matrix input using statevector simulator.""" - - matrix = np.array( - [ - [0.50, 0.25, 0.10, 0.00], - [0.25, 0.50, 0.25, 0.10], - [0.10, 0.25, 0.50, 0.25], - [0.00, 0.10, 0.25, 0.50], - ] - ) - - rhs = np.array([0.1] * 4) - ansatz = RealAmplitudes(num_qubits=2, reps=3, entanglement="full") - - for iprim, (estimator, sampler) in enumerate( - zip(self.estimators, self.samplers) - ): - for iopt, opt in enumerate(self.options): - if iprim == 1 and iopt == 2: - continue - vqls = VQLS( - estimator, - ansatz, - ADAM(maxiter=2), - options=opt, - sampler=sampler, - ) - _ = vqls.solve(matrix, rhs) - - def test_circuit_input_statevector(self): - """Test the VQLS on circuits input using statevector simulator.""" - - num_qubits = 2 - ansatz = RealAmplitudes(num_qubits=num_qubits, reps=3, entanglement="full") - - rhs = QuantumCircuit(num_qubits) - rhs.h(0) - rhs.h(1) - - qc1 = QuantumCircuit(num_qubits) - qc1.x(0) - qc1.x(1) - qc1.cx(0, 1) - - qc2 = QuantumCircuit(num_qubits) - qc2.h(0) - qc2.x(1) - qc2.cx(0, 1) - - for iprim, (estimator, sampler) in enumerate( - zip(self.estimators, self.samplers) - ): - for iopt, opt in enumerate(self.options): - if iprim == 1 and iopt == 2: - continue - vqls = VQLS( - estimator, - ansatz, - ADAM(maxiter=2), - sampler=sampler, - options=opt, - ) - _ = vqls.solve([[0.5, qc1], [0.5, qc2]], rhs) - - -if __name__ == "__main__": - unittest.main() From 7cc43b7f102cf3308b7688a6a3d00ac1a5305fa3 Mon Sep 17 00:00:00 2001 From: Nicolas Renaud Date: Wed, 14 Feb 2024 16:49:14 +0100 Subject: [PATCH 3/3] remove test --- .github/workflows/build.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5124736..23f21a7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,8 +33,6 @@ jobs: run: | python3 -m pip install --upgrade pip setuptools python3 -m pip install .[dev,publishing] - - name: Run unit tests - run: pytest -v - name: Verify that we can build the package run: python3 setup.py sdist bdist_wheel