diff --git a/example/qubo_mixed.ipynb b/example/qubo_mixed.ipynb
new file mode 100644
index 0000000..97e80a2
--- /dev/null
+++ b/example/qubo_mixed.ipynb
@@ -0,0 +1,1188 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "tags": [
+ "remove_cell"
+ ]
+ },
+ "source": [
+ "# QUBO formulation of polynomial equation"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Use case\n",
+ "\n",
+ "To illustrate the metohod we are taking the equation of the two node water system that reads:\n",
+ "\n",
+ "$$\n",
+ "-1 - x_0 + x_1 = 0 \\\\\n",
+ " 1 - x_1 = 0 \\\\\n",
+ " 2 - q x_0^2 - x_2 = 0 \\\\\n",
+ " -p x_1^2 + x_2 - x_3 = 0 \n",
+ "$$\n",
+ "\n",
+ "with $q$ and $p$ paramerers taking disrete values either 1 or 2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "\n",
+ "def nlfunc(input):\n",
+ " x0,x1,x2,x3 = input\n",
+ " q, p = parameters\n",
+ "\n",
+ " def f0():\n",
+ " return -1 - x0 + x1\n",
+ " \n",
+ " def f1():\n",
+ " return 1 - x1\n",
+ " \n",
+ " def f2():\n",
+ " return 2 - q*x0**2 - x2\n",
+ "\n",
+ " def f3():\n",
+ " return -p*x1**2 + x2 - x3\n",
+ " \n",
+ " return np.array([f0(), f1(), f2(), f3()])\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## 2. QUBO formalism for linear systems\n",
+ "\n",
+ "The Quandratic Unconstrainted Binary Optimization problem, or QUBO, allows to minimize the cost function :\n",
+ "\n",
+ "$$\n",
+ "E(x) = x^{T}Qx\n",
+ "$$\n",
+ "\n",
+ "where the variables $x_i$ are binaries, i.e. the are 0 or 1. The equation above can be rewritten as :\n",
+ "\n",
+ "$$\n",
+ "E(x) = \\sum_i Q_{ii}x_i + \\sum_{ij} Q_{ij}x_ix_j\n",
+ "$$\n",
+ "\n",
+ "that is very similar to the Ising model, basis of the quantum annealler architecture. \n",
+ "\n",
+ "### Encoding real numbers in binary variables\n",
+ "\n",
+ "In the QUBO problems, variables are binaries and we of course want to solve for real numbers in our case. There ar e different ways to encode real numbers in multiple binaries. In our case since the variables are between -1.0 and 1.0 we can use the following encoding : \n",
+ "\n",
+ "$$\n",
+ "r_i = a \\sum_n x_n 2^{n} - x_{k+n} 2^{n} \n",
+ "$$\n",
+ "\n",
+ "where $a$ is a normalization constant. THis encoding is created in the `SolutionVector` class that allows to encode/decode real numbers in a series of binaries variables. We use here the `RealUnitQbitEncoding` to obtain real numbers between -1 and 1. The number of qbit controls the precision of the reals we can obtain."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Polynomial equation\n",
+ "\n",
+ "We first write the polynomial equation as follow (https://www.nature.com/articles/s41598-019-46729-0) \n",
+ "\n",
+ "$$\n",
+ "F(X) = 0\n",
+ "$$\n",
+ "\n",
+ "with\n",
+ "\n",
+ "$$\n",
+ "F_i = P_i^{(0)} + \\sum_j P_{ij}^{(1)}x_j + \\sum_{jk} P_{ijk}^{(2)}x_j x_k = 0\n",
+ "$$\n",
+ "\n",
+ "To solve the system we minimize the residual sum of square\n",
+ "\n",
+ "$$\n",
+ "\\chi^2 = [P^{(0)} + P^{(1)} X + P^{(2)} X X.T ]^2\n",
+ "$$\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Use case\n",
+ "\n",
+ "To illustrate the metohod we are taking the equation of the two node water system that reads:\n",
+ "\n",
+ "$$\n",
+ "-1 - x_0 + x_1 = 0 \\\\\n",
+ " 1 - x_1 = 0 \\\\\n",
+ " 2 - q x_0^2 - x_2 = 0 \\\\\n",
+ " -p x_1^2 + x_2 - x_3 = 0 \\\\\n",
+ " c( M - q - p) \\rightarrow 0 \n",
+ "$$\n",
+ "\n",
+ "with $q$ and $p$ paramerers taking disrete values either 1 or 2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import sparse\n",
+ "def define_matrices():\n",
+ " \n",
+ " # system of equations\n",
+ " num_equations = 5\n",
+ " num_variables = 6\n",
+ " c = 1E-1\n",
+ " M = 14\n",
+ "\n",
+ " P0 = np.zeros((num_equations,1))\n",
+ " P0[0] = -1\n",
+ " P0[1] = 1\n",
+ " P0[2] = 2\n",
+ " P0[3] = 0\n",
+ " P0[4] = c*M\n",
+ "\n",
+ " P1 = np.zeros((num_equations, num_variables))\n",
+ " P1[0, 0] = -1\n",
+ " P1[0, 1] = 1\n",
+ "\n",
+ " P1[1, 1] = -1\n",
+ "\n",
+ " P1[2, 2] = -1\n",
+ "\n",
+ " P1[3, 2] = 1 \n",
+ " P1[3, 3] = -1\n",
+ "\n",
+ " # cost\n",
+ " P1[4,4] = -c\n",
+ " P1[4,5] = -c\n",
+ " \n",
+ "\n",
+ " P2 = np.zeros((num_equations, num_variables, num_variables))\n",
+ "\n",
+ "\n",
+ " P3 = np.zeros((num_equations, num_variables, num_variables, num_variables))\n",
+ " P3[2, 0, 0, 4] = -1\n",
+ " P3[3, 1, 1, 5] = -1\n",
+ "\n",
+ "\n",
+ " return sparse.COO(P0), sparse.COO(P1), sparse.COO(P2), sparse.COO(P3)\n",
+ "\n",
+ "matrices = define_matrices()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## 3. Solving the system\n",
+ "\n",
+ "We will use here the `SimulatedAnnealingSampler` to be able to run that code locally. Quantum solvers are available through the Leap cloud service."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from qubols.solution_vector import SolutionVector\n",
+ "from qubols.mixed_solution_vector import MixedSolutionVector\n",
+ "from qubols.encodings import PositiveQbitEncoding, RangedEfficientEncoding \n",
+ "\n",
+ "sol_vec0 = SolutionVector(4,2,PositiveQbitEncoding)\n",
+ "sol_vec1 = SolutionVector(2,3, PositiveQbitEncoding)\n",
+ "\n",
+ "x0 = sol_vec0.create_polynom_vector()\n",
+ "x1 = sol_vec1.create_polynom_vector()\n",
+ "\n",
+ "msv = MixedSolutionVector([sol_vec0, sol_vec1])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Classical solution \n",
+ "Enueration of the possible values using Newton Raphson"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "(0.0, 0.0) [-2.7752569e-17 1.0000000e+00 2.0000000e+00 2.0000000e+00]\n",
+ "(0.0, 1.0) [-8.32647404e-17 1.00000000e+00 2.00000000e+00 1.00000000e+00]\n",
+ "(0.0, 2.0) [1.22739386e-22 1.00000000e+00 2.00000000e+00 4.08364453e-11]\n",
+ "(0.0, 3.0) [-4.28301843e-22 1.00000000e+00 2.00000000e+00 -1.00000000e+00]\n",
+ "(0.0, 4.0) [-5.55088879e-17 1.00000000e+00 2.00000000e+00 -2.00000000e+00]\n",
+ "(0.0, 5.0) [ 2.22039588e-17 1.00000000e+00 2.00000000e+00 -3.00000000e+00]\n",
+ "(0.0, 6.0) [-1.11020102e-16 1.00000000e+00 2.00000000e+00 -4.00000000e+00]\n",
+ "(0.0, 7.0) [ 3.84288726e-21 1.00000000e+00 2.00000000e+00 -5.00000000e+00]\n",
+ "(1.0, 0.0) [-1.1560366e-21 1.0000000e+00 2.0000000e+00 2.0000000e+00]\n",
+ "(1.0, 1.0) [-1.0496405e-21 1.0000000e+00 2.0000000e+00 1.0000000e+00]\n",
+ "(1.0, 2.0) [-4.85725227e-17 1.00000000e+00 2.00000000e+00 1.67282854e-13]\n",
+ "(1.0, 3.0) [ 5.08857722e-17 1.00000000e+00 2.00000000e+00 -1.00000000e+00]\n",
+ "(1.0, 4.0) [ 5.20429198e-17 1.00000000e+00 2.00000000e+00 -2.00000000e+00]\n",
+ "(1.0, 5.0) [ 4.44120629e-17 1.00000000e+00 2.00000000e+00 -3.00000000e+00]\n",
+ "(1.0, 6.0) [ 8.32679561e-17 1.00000000e+00 2.00000000e+00 -4.00000000e+00]\n",
+ "(1.0, 7.0) [ 3.96290046e-18 1.00000000e+00 2.00000000e+00 -5.00000000e+00]\n",
+ "(2.0, 0.0) [-5.55114563e-17 1.00000000e+00 2.00000000e+00 2.00000000e+00]\n",
+ "(2.0, 1.0) [-7.63270989e-17 1.00000000e+00 2.00000000e+00 1.00000000e+00]\n",
+ "(2.0, 2.0) [-8.90039877e-22 1.00000000e+00 2.00000000e+00 -1.75487402e-11]\n",
+ "(2.0, 3.0) [-1.85011689e-17 1.00000000e+00 2.00000000e+00 -1.00000000e+00]\n",
+ "(2.0, 4.0) [-2.02449224e-23 1.00000000e+00 2.00000000e+00 -2.00000000e+00]\n",
+ "(2.0, 5.0) [-4.4405397e-17 1.0000000e+00 2.0000000e+00 -3.0000000e+00]\n",
+ "(2.0, 6.0) [ 5.32000675e-17 1.00000000e+00 2.00000000e+00 -4.00000000e+00]\n",
+ "(2.0, 7.0) [-4.75824941e-17 1.00000000e+00 2.00000000e+00 -5.00000000e+00]\n",
+ "(3.0, 0.0) [-1.46401921e-21 1.00000000e+00 2.00000000e+00 2.00000000e+00]\n",
+ "(3.0, 1.0) [-5.55099715e-17 1.00000000e+00 2.00000000e+00 1.00000000e+00]\n",
+ "(3.0, 2.0) [ 5.55142572e-17 1.00000000e+00 2.00000000e+00 -6.46234854e-27]\n",
+ "(3.0, 3.0) [ 5.08848077e-17 1.00000000e+00 2.00000000e+00 -1.00000000e+00]\n",
+ "(3.0, 4.0) [-5.55109991e-17 1.00000000e+00 2.00000000e+00 -2.00000000e+00]\n",
+ "(3.0, 5.0) [ 6.10615705e-17 1.00000000e+00 2.00000000e+00 -3.00000000e+00]\n",
+ "(3.0, 6.0) [ 4.78972697e-21 1.00000000e+00 2.00000000e+00 -4.00000000e+00]\n",
+ "(3.0, 7.0) [ 4.06426711e-17 1.00000000e+00 2.00000000e+00 -5.00000000e+00]\n",
+ "(4.0, 0.0) [1.38775628e-17 1.00000000e+00 2.00000000e+00 2.00000000e+00]\n",
+ "(4.0, 1.0) [2.7368046e-24 1.0000000e+00 2.0000000e+00 1.0000000e+00]\n",
+ "(4.0, 2.0) [2.12275225e-21 1.00000000e+00 2.00000000e+00 5.16987883e-26]\n",
+ "(4.0, 3.0) [ 3.70073855e-17 1.00000000e+00 2.00000000e+00 -1.00000000e+00]\n",
+ "(4.0, 4.0) [-2.77546146e-17 1.00000000e+00 2.00000000e+00 -2.00000000e+00]\n",
+ "(4.0, 5.0) [ 1.94658863e-21 1.00000000e+00 2.00000000e+00 -3.00000000e+00]\n",
+ "(4.0, 6.0) [-1.16446028e-21 1.00000000e+00 2.00000000e+00 -4.00000000e+00]\n",
+ "(4.0, 7.0) [ 3.17214795e-17 1.00000000e+00 2.00000000e+00 -5.00000000e+00]\n",
+ "(5.0, 0.0) [-3.87530886e-22 1.00000000e+00 2.00000000e+00 2.00000000e+00]\n",
+ "(5.0, 1.0) [-2.2204401e-16 1.0000000e+00 2.0000000e+00 1.0000000e+00]\n",
+ "(5.0, 2.0) [-4.68479879e-23 1.00000000e+00 2.00000000e+00 1.73916437e-13]\n",
+ "(5.0, 3.0) [ 6.93890163e-17 1.00000000e+00 2.00000000e+00 -1.00000000e+00]\n",
+ "(5.0, 4.0) [-5.55094392e-17 1.00000000e+00 2.00000000e+00 -2.00000000e+00]\n",
+ "(5.0, 5.0) [-9.01947702e-17 1.00000000e+00 2.00000000e+00 -3.00000000e+00]\n",
+ "(5.0, 6.0) [ 1.38795659e-17 1.00000000e+00 2.00000000e+00 -4.00000000e+00]\n",
+ "(5.0, 7.0) [ 3.17208077e-17 1.00000000e+00 2.00000000e+00 -5.00000000e+00]\n",
+ "(6.0, 0.0) [-1.59079756e-21 1.00000000e+00 2.00000000e+00 2.00000000e+00]\n",
+ "(6.0, 1.0) [-2.85141443e-21 1.00000000e+00 2.00000000e+00 1.00000000e+00]\n",
+ "(6.0, 2.0) [-7.59232249e-22 1.00000000e+00 2.00000000e+00 -1.03397577e-25]\n",
+ "(6.0, 3.0) [ 1.11018824e-16 1.00000000e+00 2.00000000e+00 -1.00000000e+00]\n",
+ "(6.0, 4.0) [-7.73711141e-22 1.00000000e+00 2.00000000e+00 -2.00000000e+00]\n",
+ "(6.0, 5.0) [ 8.88204353e-17 1.00000000e+00 2.00000000e+00 -3.00000000e+00]\n",
+ "(6.0, 6.0) [-1.38499977e-22 1.00000000e+00 2.00000000e+00 -4.00000000e+00]\n",
+ "(6.0, 7.0) [ 5.55119882e-17 1.00000000e+00 2.00000000e+00 -5.00000000e+00]\n",
+ "(7.0, 0.0) [2.7755762e-17 1.0000000e+00 2.0000000e+00 2.0000000e+00]\n",
+ "(7.0, 1.0) [8.23070559e-22 1.00000000e+00 2.00000000e+00 1.00000000e+00]\n",
+ "(7.0, 2.0) [2.0599897e-21 1.0000000e+00 2.0000000e+00 0.0000000e+00]\n",
+ "(7.0, 3.0) [ 3.70082879e-17 1.00000000e+00 2.00000000e+00 -1.00000000e+00]\n",
+ "(7.0, 4.0) [ 1.38797206e-17 1.00000000e+00 2.00000000e+00 -2.00000000e+00]\n",
+ "(7.0, 5.0) [ 4.44102531e-17 1.00000000e+00 2.00000000e+00 -3.00000000e+00]\n",
+ "(7.0, 6.0) [ 2.78297809e-21 1.00000000e+00 2.00000000e+00 -4.00000000e+00]\n",
+ "(7.0, 7.0) [ 5.55087177e-17 1.00000000e+00 2.00000000e+00 -5.00000000e+00]\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/nico/QuantumApplicationLab/QuantumNewtonRaphson/quantum_newton_raphson/utils.py:74: SparseEfficiencyWarning: spsolve requires A be CSC or CSR matrix format\n",
+ " warn(\"spsolve requires A be CSC or CSR matrix format\", SparseEfficiencyWarning)\n"
+ ]
+ }
+ ],
+ "source": [
+ "from quantum_newton_raphson.newton_raphson import newton_raphson\n",
+ "import itertools\n",
+ "\n",
+ "values = sol_vec1.encoded_reals[0].get_possible_values()\n",
+ "parameters_list = itertools.product(values, repeat=2)\n",
+ "\n",
+ "for parameters in parameters_list:\n",
+ " initial_point = np.random.rand(4)\n",
+ " res = newton_raphson(nlfunc, initial_point)\n",
+ " assert np.allclose(nlfunc(res.solution), 0)\n",
+ " print(parameters, res.solution)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from qubols.qubo_poly_mixed_variables import QUBO_POLY_MIXED \n",
+ "qubo = QUBO_POLY_MIXED(msv)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[0.0, 1.0, 2.0, 1.0] [7.0, 1.0]\n"
+ ]
+ }
+ ],
+ "source": [
+ "# create the bqm\n",
+ "bqm = qubo.create_bqm(matrices, strength=1000)\n",
+ "\n",
+ "# add constraint\n",
+ "slacks2 = bqm.add_linear_inequality_constraint(qubo.all_expr[3], lagrange_multiplier=1, label=\"head2\", lb=1, ub=2)\n",
+ "\n",
+ "# sample\n",
+ "sampleset = qubo.sample_bqm(bqm, num_reads=1000)\n",
+ "\n",
+ "# decode\n",
+ "sol, param = qubo.decode_solution(sampleset.lowest())\n",
+ "print(sol, param)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([0., 0., 0., 0.])"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "parameters = param\n",
+ "nlfunc(sol)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3.8.0 ('qubols')",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.0"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "390591a6667b05d6f83558ed597f55be1305d4de992db830679d199a6a0e520c"
+ }
+ },
+ "widgets": {
+ "application/vnd.jupyter.widget-state+json": {
+ "state": {
+ "17046f96803d48aa8c63b99a5c89e6f3": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "1a46e33438a648dd839fe5fd43b9582b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "1f812fe9a02b41b885f01e3190957acf": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": "\n \". . . . right \"\n ",
+ "grid_template_columns": "20% 20% 20% 20% 20%",
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "100%"
+ }
+ },
+ "20439ee3a84741dc9a137f7964898fc3": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_f0e6a746eff140269e915ef65de640c7",
+ "placeholder": "",
+ "style": "IPY_MODEL_96316857896d44328b3898d849594ae7",
+ "value": "
Status
"
+ }
+ },
+ "246d39f98fdb4892bc1d5bfb88d2f1cd": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "27e0478b2a9c4533b2e67eac937cbebc": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HBoxModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_ac5a0f78ef8140a2abdf035fd1751936",
+ "IPY_MODEL_5ff6f36eaa894a339210fc29fdbeedcf",
+ "IPY_MODEL_20439ee3a84741dc9a137f7964898fc3",
+ "IPY_MODEL_eef64edafd8f47c885da65fa3ca0ab8a",
+ "IPY_MODEL_a38db3ffdfc848c0b0150e42b3509be5"
+ ],
+ "layout": "IPY_MODEL_fc018f99fbb44aa9beb54a8e6be5209e"
+ }
+ },
+ "2f981df37e914685992f4564103ef872": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "3aa67247d1a9433f87b13ce1370c8b1c": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "190px"
+ }
+ },
+ "40a8f99fef5b4aad89f533edcb091c3f": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "ButtonStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "ButtonStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "button_color": null,
+ "font_weight": ""
+ }
+ },
+ "46f75da5f7ab4f33b4df8618ccffde6b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "5ff6f36eaa894a339210fc29fdbeedcf": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_9e036ff6f31e4efb9471d371db06f533",
+ "placeholder": "",
+ "style": "IPY_MODEL_1a46e33438a648dd839fe5fd43b9582b",
+ "value": "Backend
"
+ }
+ },
+ "608e06da96f840e890006ad286afc34b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_74038cd5fbe8491ba5457f6cc81f7b5a",
+ "placeholder": "",
+ "style": "IPY_MODEL_8569084253df4279b752a85c0b99027b",
+ "value": "Circuit Properties
"
+ }
+ },
+ "74038cd5fbe8491ba5457f6cc81f7b5a": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": "0px 0px 10px 0px",
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "8569084253df4279b752a85c0b99027b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "917c693fd8d84f2e99f59d75cd5062c2": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "GridBoxModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "GridBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "GridBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_b7e87c3bbc404502ab1550d64f86c473"
+ ],
+ "layout": "IPY_MODEL_1f812fe9a02b41b885f01e3190957acf"
+ }
+ },
+ "96316857896d44328b3898d849594ae7": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "9e036ff6f31e4efb9471d371db06f533": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "145px"
+ }
+ },
+ "a38db3ffdfc848c0b0150e42b3509be5": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_2f981df37e914685992f4564103ef872",
+ "placeholder": "",
+ "style": "IPY_MODEL_246d39f98fdb4892bc1d5bfb88d2f1cd",
+ "value": "Message
"
+ }
+ },
+ "ac5a0f78ef8140a2abdf035fd1751936": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_3aa67247d1a9433f87b13ce1370c8b1c",
+ "placeholder": "",
+ "style": "IPY_MODEL_46f75da5f7ab4f33b4df8618ccffde6b",
+ "value": "Job ID
"
+ }
+ },
+ "b7e87c3bbc404502ab1550d64f86c473": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "ButtonModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "ButtonModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "ButtonView",
+ "button_style": "primary",
+ "description": "Clear",
+ "disabled": false,
+ "icon": "",
+ "layout": "IPY_MODEL_f6a39516121743099bece32bc0c3c696",
+ "style": "IPY_MODEL_40a8f99fef5b4aad89f533edcb091c3f",
+ "tooltip": ""
+ }
+ },
+ "eef64edafd8f47c885da65fa3ca0ab8a": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_ef270ca07615429ab689824b66fdb1ff",
+ "placeholder": "",
+ "style": "IPY_MODEL_17046f96803d48aa8c63b99a5c89e6f3",
+ "value": "Queue
"
+ }
+ },
+ "ef270ca07615429ab689824b66fdb1ff": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "70px"
+ }
+ },
+ "f0e6a746eff140269e915ef65de640c7": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "95px"
+ }
+ },
+ "f6a39516121743099bece32bc0c3c696": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": "right",
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": "0px 0px 0px 0px",
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "70px"
+ }
+ },
+ "fc018f99fbb44aa9beb54a8e6be5209e": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": "0px 0px 0px 37px",
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "600px"
+ }
+ }
+ },
+ "version_major": 2,
+ "version_minor": 0
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/example/qubols.ipynb b/example/qubo_mixed_floats.ipynb
similarity index 51%
rename from example/qubols.ipynb
rename to example/qubo_mixed_floats.ipynb
index 6c764f6..65a8edd 100644
--- a/example/qubols.ipynb
+++ b/example/qubo_mixed_floats.ipynb
@@ -8,67 +8,53 @@
]
},
"source": [
- "# QUBO formulation of the Redundant Calibration"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "import numpy as np\n",
- "np.random.seed(20)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [],
- "source": [
- "size = 4\n",
- "A = np.random.rand(size,size)\n",
- "A = 0.1*(A+A.T)\n",
- "# A /= np.linalg.norm(A)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [],
- "source": [
- "b = np.random.rand(size,1)\n",
- "# b /= np.linalg.norm(b)"
+ "# QUBO formulation of polynomial equation"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Classical Solution\n",
+ "# Use case\n",
+ "\n",
+ "To illustrate the metohod we are taking the equation of the two node water system that reads:\n",
"\n",
- "The solution of such a small system can be obtained by a least square as implemented in numpy"
+ "$$\n",
+ " 0.5 - x_0 + x_1 = 0 \\\\\n",
+ " 1 - x_1 = 0 \\\\\n",
+ " 2 - q x_0^2 - x_2 = 0 \\\\\n",
+ " -p x_1^2 + x_2 - x_3 = 0 \n",
+ "$$\n",
+ "\n",
+ "with $q$ and $p$ paramerers taking disrete values either 1 or 2"
]
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 1,
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[-0.37072381 6.30320449 -3.71869512 0.92589866]\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
- "npsol = np.linalg.solve(A,b)\n",
- "npsol = np.asarray(npsol).flatten()\n",
- "print(npsol)"
+ "import numpy as np\n",
+ "\n",
+ "def nlfunc(input):\n",
+ " x0,x1,x2,x3 = input\n",
+ " q, p = parameters\n",
+ "\n",
+ " def f0():\n",
+ " return 0.5 - x0 + x1\n",
+ " \n",
+ " def f1():\n",
+ " return 1 - x1\n",
+ " \n",
+ " def f2():\n",
+ " return 2 - q*x0**2 - x2\n",
+ "\n",
+ " def f3():\n",
+ " return -p*x1**2 + x2 - x3\n",
+ " \n",
+ " return np.array([f0(), f1(), f2(), f3()])\n",
+ "\n"
]
},
{
@@ -106,15 +92,42 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "### Linear systems\n",
+ "### Polynomial equation\n",
+ "\n",
+ "We first write the polynomial equation as follow (https://www.nature.com/articles/s41598-019-46729-0) \n",
+ "\n",
+ "$$\n",
+ "F(X) = 0\n",
+ "$$\n",
"\n",
- "To solve a linear system $Ax=b$ with QUBO we need to minimize the following loss \n",
+ "with\n",
"\n",
"$$\n",
- "E(x) = ||Ax-b||^2 =(Ax-b)^T (Ax-b) = x^T A^T A x-b^T A x-A x b^T+ b^T b = x^T Q x + ||b||^2\n",
+ "F_i = P_i^{(0)} + \\sum_j P_{ij}^{(1)}x_j + \\sum_{jk} P_{ijk}^{(2)}x_j x_k = 0\n",
"$$\n",
"\n",
- "We can ignore the last terms as it doesn't contribute to the optimization process. The $Q$ matrix can be defined through the different terms of the expression. This is achieved by the `create_qubo_matrix` methods that returns a `dict` containing the weights (diagonal terms) and strengths (off diagonal terms) of the $Q$ matrix. "
+ "To solve the system we minimize the residual sum of square\n",
+ "\n",
+ "$$\n",
+ "\\chi^2 = [P^{(0)} + P^{(1)} X + P^{(2)} X X.T ]^2\n",
+ "$$\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Use case\n",
+ "\n",
+ "To illustrate the metohod we are taking the equation of the two node water system that reads:\n",
+ "\n",
+ "$$\n",
+ " 0.5 - x_0 + x_1 = 0 \\\\\n",
+ " 1 - x_1 = 0 \\\\\n",
+ " 2 - q x_0^2 - x_2 = 0 \\\\\n",
+ " -p x_1^2 + x_2 - x_3 = 0 \\\\\n",
+ " c( M - q - p) \\rightarrow 0 \n",
+ "$$"
]
},
{
@@ -128,37 +141,86 @@
},
{
"cell_type": "code",
- "execution_count": 43,
+ "execution_count": 2,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/nico/QuantumApplicationLab/qubols/qubols/encodings.py:264: FutureWarning: `rcond` parameter will change to the default of machine precision times ``max(M, N)`` where M and N are the input matrix dimensions.\n",
+ "To use the future default and silence this warning we advise to pass `rcond=None`, to keep using the old, explicitly pass `rcond=-1`.\n",
+ " coefs, res, rank, s = np.linalg.lstsq(A, self.discrete_values)\n"
+ ]
+ }
+ ],
+ "source": [
+ "from qubols.solution_vector import SolutionVector_V2 as SolutionVector\n",
+ "from qubols.mixed_solution_vector import MixedSolutionVector_V2 as MixedSolutionVector\n",
+ "from qubols.encodings import PositiveQbitEncoding, DiscreteValuesEncoding, RangedEfficientEncoding\n",
+ "import numpy as np \n",
+ "\n",
+ "\n",
+ "vals = np.array([0.0559702820337183,\n",
+ " 0.207808449766538,\n",
+ " 0.23298897621448805,\n",
+ " 0.38482714394730777])\n",
+ "\n",
+ "# vals = np.array([0.025376709013691795,\n",
+ "# 0.07395128696628388,\n",
+ "# 0.13854430584226343,\n",
+ "# 0.18711888379485553])\n",
+ "\n",
+ "# vals = np.array([0.25, 0.5])\n",
+ "\n",
+ "sol_vec0 = SolutionVector(size=4, encoding=RangedEfficientEncoding(nqbit=6, range=2, offset=0, var_base_name=\"x\"))\n",
+ "sol_vec1 = SolutionVector(size=2, encoding=DiscreteValuesEncoding(vals, 2, \"x\"))\n",
+ "\n",
+ "\n",
+ "msv = MixedSolutionVector([sol_vec0, sol_vec1])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[0.05597028203371821,\n",
+ " 0.20780844976653792,\n",
+ " 0.23298897621448816,\n",
+ " 0.3848271439473079]"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "from qubols.qubols import QUBOLS\n",
- "from qubols.encodings import RangedEfficientEncoding\n",
- "import dimod\n",
- "options = {'num_reads':20, 'num_qbits':6, 'sampler':dimod.ExactSolver(), \n",
- " 'encoding': RangedEfficientEncoding, 'range':10.0, 'offset':[0,0,0,0]}\n",
- "qubols= QUBOLS(options)\n",
- "sol_num = qubols.solve(A, b)"
+ "sol_vec1.encoded_reals[0].get_possible_values()"
]
},
{
"cell_type": "code",
- "execution_count": 44,
+ "execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
- ""
+ ""
]
},
- "execution_count": 44,
+ "execution_count": 4,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
- "image/png": "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oRhLs8LCwjRz5kwNHz7cjJgAAISUkLlqxma1aOHsgZKuLEz9mkWG7g3/SjGWZkXHJeipp56ihAAA0EFCpohI0ozBKXr50ZHqbv/7NI0hiw5F9FdS7/56+sc/VFJSkokJAQAILSEzNfO1GYNTdFf0Ze07dlbhyRmt3lkVAAC0v5AqIh6PR1u2bNHWrVtls9n05JN3qXv3LmbHAgAgZIVMEamtrVVRUZG++uorSdLQoUPVpQslBAAAM4VEETl27JhWrlypy5cvKyIiQrNmzdKQIUPMjgUAQMgL+iLyt7/9TVu3bpUkdevWTQUFBYyEAADgJ4K+iISFXflHHDVqlKZPn67w8HCTEwEAgK/5vIi4XC6NHj1a+/fv16efftohe3S0tLR4C8i4ceOUlpamjIwMn78uAABoG5/vI/KLX/xCqampvn4ZSVeuinn//ff1yiuvqLm5WZJksVgoIQAA+CmfFpENGzZo06ZNev755335MpIkh8OhZcuWafv27aqqqlJZWZnPXxMAANwZn03NVFZWat68eXr33XcVExPjq5eRJH355Zd699131dDQoMjISM2ZM0cDBw706WsCAIA755MiYhiGHn/8cf3whz9UVlaWTp482arnuVwuuVwu72On03nT891ut0pLS7Vz505JUkpKivLz85WYmHjb2QEAQMdpUxF59tln9bvf/e6m53z++efatGmTamtrtWDBgjaFWbRokZ577rlrjt+okJSUlOiTTz6RJGVlZWnSpEkKCwu7ZYEBAAC+8/XnsGF8+37317IYrTnr/1RXV+vChQs3PSczM1MPPfSQ1qxZI4vl7/dvcbvdstlseuSRR/T6669f97nfHhEpLy9nigUAgAB1+vRppaWl3fScNhWR1jp16tRVoxIVFRWaPn26CgsLNXr06FuG+prH41FFRYXi4uKuKjXf5nQ6lZ6ertOnTys+Pv6O8+P6eJ87Bu9zx+B97hi8zx3D395nwzBUW1ur1NRUWa03vy7GJ2tEevbsedXj2NhYSVKfPn1aXUIkyWq1tun8+Ph4v/gXEOx4nzsG73PH4H3uGLzPHcOf3me73d6q83y+jwgAAMCNdMgW7717927VghUAABBagmJEJDIyUgsXLlRkZKTZUYIa73PH4H3uGLzPHYP3uWME8vvsk8WqAAAArREUIyIAACAwUUQAAIBpKCIAAMA0FBEAAGCaoC0iLpdLw4cPl8Vi0b59+8yOE1ROnjyp73//+8rIyFB0dLT69OmjhQsXqqmpyexoAe8Pf/iDevfuraioKI0ePVq7du0yO1LQWbRoke655x7FxcUpOTlZOTk5+uKLL8yOFdR++9vfymKx6OmnnzY7StApLy/Xo48+qi5duig6OlpDhgzx3oMtUARtEfnFL36h1NRUs2MEpbKyMnk8Hi1evFiHDh3S//zP/+hPf/qTfvWrX5kdLaAtX75czzzzjBYuXKi9e/dq2LBhmj59uqqqqsyOFlS2bNmi+fPn66OPPlJJSYmam5s1bdo01dfXmx0tKO3evVuLFy/W0KFDzY4SdC5duqSxY8cqPDxcGzZs0OHDh/Xf//3fSkhIMDta2xhBaP369Ub//v2NQ4cOGZKMTz/91OxIQe8///M/jYyMDLNjBLTs7Gxj/vz53sdut9tITU01Fi1aZGKq4FdVVWVIMrZs2WJ2lKBTW1tr9O3b1ygpKTEmTJhg/OxnPzM7UlD55S9/aYwbN87sGHcs6EZEKisrNW/ePL3xxhuKiYkxO07IcDgcSkxMNDtGwGpqatKePXs0ZcoU7zGr1aopU6Zo586dJiYLfg6HQ5L4/fWB+fPna+bMmVf9XqP9rF69WllZWSooKFBycrJGjBihV155xexYbRZURcQwDD3++OP64Q9/qKysLLPjhIyjR4/qxRdf1A9+8AOzowSs8+fPy+12q1u3blcd79atm86dO2dSquDn8Xj09NNPa+zYsRo8eLDZcYLKO++8o71792rRokVmRwlax48f18svv6y+ffvqvffe049+9CP99Kc/1euvv252tDYJiCLy7LPPymKx3PSrrKxML774ompra7VgwQKzIwek1r7P31ReXq4ZM2aooKBA8+bNMyk5cHvmz5+vgwcP6p133jE7SlA5ffq0fvazn+mtt95SVFSU2XGClsfj0ciRI/Wb3/xGI0aM0FNPPaV58+bpT3/6k9nR2qRDbnp3p/71X/9Vjz/++E3PyczM1AcffKCdO3des9d+VlaWHnnkkYBriR2tte/z1yoqKjRp0iTde++9WrJkiY/TBbeuXbvKZrOpsrLyquOVlZXq3r27SamC249//GOtXbtWW7duVVpamtlxgsqePXtUVVWlkSNHeo+53W5t3bpVL730klwul2w2m4kJg0NKSooGDhx41bEBAwaoqKjIpES3JyCKSFJSkpKSkm553u9//3v9x3/8h/dxRUWFpk+fruXLl2v06NG+jBgUWvs+S1dGQiZNmqRRo0Zp6dKlsloDYnDNb0VERGjUqFEqLS1VTk6OpCt/7ZSWlurHP/6xueGCjGEY+slPfqLi4mJt3rxZGRkZZkcKOpMnT9aBAweuOvbEE0+of//++uUvf0kJaSdjx4695tLzL7/8Ur169TIp0e0JiCLSWj179rzqcWxsrCSpT58+/MXTjsrLyzVx4kT16tVLzz//vKqrq73f46/32/fMM8/oscceU1ZWlrKzs/XCCy+ovr5eTzzxhNnRgsr8+fP1l7/8RatWrVJcXJx3DY7dbld0dLTJ6YJDXFzcNWtuOnXqpC5durAWpx39/Oc/17333qvf/OY3euihh7Rr1y4tWbIk4Eaog6qIoGOUlJTo6NGjOnr06DUFz+Bmzrft4YcfVnV1tX7961/r3LlzGj58uDZu3HjNAlbcmZdfflmSNHHixKuOL1269JZTk4A/ueeee1RcXKwFCxbo3//935WRkaEXXnhBjzzyiNnR2sRi8MkBAABMwsQ+AAAwDUUEAACYhiICAABMQxEBAACmoYgAAADTUEQAAIBpKCIAAMA0FBEAAGAaiggAADANRQQAAJiGIgIAAExDEQEAAKb5/9nGHOA+Mv0RAAAAAElFTkSuQmCC",
+ "image/png": "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e48lnmvrC5999pm++OKLkF/2VrLy+iorK+XxeNTU1BQsVvx+vzZt2hR3R1ZPmL226upqtba2asuWLRozZowkad26dero6AgWJGZs27ZNkhL2vQunf//+GjNmjJqamlRXVyfp1G3spqYm3XXXXWHXVFdXq6mpSfPmzQseW7NmTUJ+vuLRk2vr6uTJk/rggw90/fXXW7jTxKiuru7WWpuK37e+tG3btqT+fEViGIa+973v6eWXX9b69etVWVkZc01Sfu4siwJnuM8++8wYNmyYcc011xifffaZcfDgweDr9HMuuOACY9OmTcFjd9xxhzFkyBBj3bp1xrvvvmtUV1cb1dXVybiEqD755BNj69atxuLFi438/Hxj69atxtatW42jR48Gz7nggguMl156yTAMwzh69Kjxb//2b0Zzc7Oxd+9eY+3atcbo0aON8847zzh+/HiyLiOieK/PMAzjP/7jP4zCwkLjlVdeMd5//31j6tSpRmVlpfHVV18l4xIimjx5snHppZcamzZtMjZu3Gicd955xsyZM4Nf7/rf5e7du40f/vCHxrvvvmvs3bvXeOWVV4yhQ4caV111VbIuIeiFF14wHA6HsXz5cuPDDz80br/9dqOwsNDwer2GYRjGt771LWPhwoXB8998803jjDPOMJYsWWJ89NFHxqJFi4ycnBzjgw8+SNYlRBTvtS1evNj405/+ZOzZs8fYsmWLMWPGDMPpdBo7duxI1iVEdPTo0eDPlCTj5z//ubF161bjk08+MQzDMBYuXGh861vfCp7/5z//2cjLyzO+//3vGx999JHx2GOPGf369TNWr16drEuIKt7rW7p0qbFy5Urj448/Nj744APj7rvvNux2u7F27dpkXUJEd955p+F2u43169eH/F47duxY8JxU+LmjeOmhp59+2pAU9tVp7969hiTj9ddfDx776quvjH/91381Bg4caOTl5Rk33nhjSMGTKmbNmhX22k6/FknG008/bRiGYRw7dsy49tprjZKSEiMnJ8c4++yzjTlz5gT/R5xq4r0+wzjVLv3AAw8YZWVlhsPhMK655hpj165did98DF988YUxc+ZMIz8/33C5XMZtt90WUpR1/e9y3759xlVXXWUUFRUZDofDGDZsmPH973/f8Pl8SbqCUI8++qgxZMgQo3///sbYsWONt99+O/i1CRMmGLNmzQo5/3e/+51x/vnnG/379zcuuugi449//GOCd2xePNc2b9684LllZWXG9ddfb7z33ntJ2HVsna3BXV+d1zNr1ixjwoQJ3dZUVVUZ/fv3N4YOHRrys5dq4r2+hx56yDj33HMNp9NpFBUVGRMnTjTWrVuXnM3HEOn32unfj1T4ubP9fbMAAABpgW4jAACQViheAABAWqF4AQAAaYXiBQAApBWKFwAAkFYoXgAAQFqheAEAAGmF4gUAAKQVihcAAJBWKF4AAEBaoXgBAABpheIFAACklf8P5I/gJgmAEaUAAAAASUVORK5CYII=",
"text/plain": [
""
]
@@ -168,9 +230,126 @@
}
],
"source": [
- "import matplotlib.pyplot as plt\n",
- "plt.scatter(npsol, sol_num)\n",
- "plt.axline( (0,0),slope=1,linestyle='--',color='gray')"
+ "val = sol_vec0.encoded_reals[0].get_possible_values()\n",
+ "import matplotlib.pyplot as plt \n",
+ "plt.scatter(val, val)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Classical solution \n",
+ "Enueration of the possible values using Newton Raphson"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "(0.05597028203371821, 0.05597028203371821) [1.5 1. 1.87406687 1.81809658]\n",
+ "(0.05597028203371821, 0.20780844976653792) [1.5 1. 1.87406687 1.66625842]\n",
+ "(0.05597028203371821, 0.23298897621448816) [1.5 1. 1.87406687 1.64107789]\n",
+ "(0.05597028203371821, 0.3848271439473079) [1.5 1. 1.87406687 1.48923972]\n",
+ "(0.20780844976653792, 0.05597028203371821) [1.5 1. 1.53243099 1.47646071]\n",
+ "(0.20780844976653792, 0.20780844976653792) [1.5 1. 1.53243099 1.32462254]\n",
+ "(0.20780844976653792, 0.23298897621448816) [1.5 1. 1.53243099 1.29944201]\n",
+ "(0.20780844976653792, 0.3848271439473079) [1.5 1. 1.53243099 1.14760384]\n",
+ "(0.23298897621448816, 0.05597028203371821) [1.5 1. 1.4757748 1.41980452]\n",
+ "(0.23298897621448816, 0.20780844976653792) [1.5 1. 1.4757748 1.26796635]\n",
+ "(0.23298897621448816, 0.23298897621448816) [1.5 1. 1.4757748 1.24278583]\n",
+ "(0.23298897621448816, 0.3848271439473079) [1.5 1. 1.4757748 1.09094766]\n",
+ "(0.3848271439473079, 0.05597028203371821) [1.5 1. 1.13413893 1.07816864]\n",
+ "(0.3848271439473079, 0.20780844976653792) [1.5 1. 1.13413893 0.92633048]\n",
+ "(0.3848271439473079, 0.23298897621448816) [1.5 1. 1.13413893 0.90114995]\n",
+ "(0.3848271439473079, 0.3848271439473079) [1.5 1. 1.13413893 0.74931178]\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/nico/QuantumApplicationLab/QuantumNewtonRaphson/quantum_newton_raphson/utils.py:74: SparseEfficiencyWarning: spsolve requires A be CSC or CSR matrix format\n",
+ " warn(\"spsolve requires A be CSC or CSR matrix format\", SparseEfficiencyWarning)\n"
+ ]
+ }
+ ],
+ "source": [
+ "from quantum_newton_raphson.newton_raphson import newton_raphson\n",
+ "import itertools\n",
+ "\n",
+ "values = sol_vec1.encoded_reals[0].get_possible_values()\n",
+ "parameters_list = itertools.product(values, repeat=2)\n",
+ "\n",
+ "for parameters in parameters_list:\n",
+ " initial_point = np.random.rand(4)\n",
+ " res = newton_raphson(nlfunc, initial_point)\n",
+ " assert np.allclose(nlfunc(res.solution), 0)\n",
+ " print(parameters, res.solution)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Quantum SOolution"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import sparse\n",
+ "def define_matrices():\n",
+ " \n",
+ " # system of equations\n",
+ " num_equations = 5\n",
+ " num_variables = 6\n",
+ " c = 1E-1\n",
+ " M = 2*sol_vec1.encoded_reals[0].get_max_value()\n",
+ "\n",
+ " P0 = np.zeros((num_equations,1))\n",
+ " P0[0] = 1/2\n",
+ " P0[1] = 1\n",
+ " P0[2] = 2\n",
+ " P0[3] = 0\n",
+ " P0[4] = c*M\n",
+ "\n",
+ " P1 = np.zeros((num_equations, num_variables))\n",
+ " P1[0, 0] = -1\n",
+ " P1[0, 1] = 1\n",
+ "\n",
+ " P1[1, 1] = -1\n",
+ "\n",
+ " P1[2, 2] = -1\n",
+ "\n",
+ " P1[3, 2] = 1 \n",
+ " P1[3, 3] = -1\n",
+ "\n",
+ " # cost\n",
+ " P1[4,4] = -c\n",
+ " P1[4,5] = -c\n",
+ " \n",
+ "\n",
+ " P2 = np.zeros((num_equations, num_variables, num_variables))\n",
+ "\n",
+ "\n",
+ " P3 = np.zeros((num_equations, num_variables, num_variables, num_variables))\n",
+ " P3[2, 0, 0, 4] = -1\n",
+ " P3[3, 1, 1, 5] = -1\n",
+ "\n",
+ "\n",
+ " return sparse.COO(P0), sparse.COO(P1), sparse.COO(P2), sparse.COO(P3)\n",
+ "\n",
+ "matrices = define_matrices()"
]
},
{
@@ -179,63 +358,74 @@
"metadata": {},
"outputs": [],
"source": [
- "from qubols.aequbols import AEQUBOLS"
+ "from qubols.qubo_poly_mixed_variables import QUBO_POLY_MIXED \n",
+ "qubo = QUBO_POLY_MIXED(msv)"
]
},
{
"cell_type": "code",
- "execution_count": 45,
+ "execution_count": 8,
"metadata": {},
"outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/nico/miniconda3/envs/vitens_wntr_1/lib/python3.9/site-packages/dimod/binary/binary_quadratic_model.py:759: UserWarning: For constraints with fractional coefficients, multiply both sides of the inequality by an appropriate factor of ten to attain or approximate integer coefficients. \n",
+ " warnings.warn(\"For constraints with fractional coefficients, \"\n"
+ ]
+ },
{
"name": "stdout",
"output_type": "stream",
"text": [
- "0 [0.0, 0.0, 0.0, 0.0] 10.0\n",
- "1 [-0.5568358556771333, 6.378011777958716, -3.5394037026882863, 1.047337843009113] [6.1553951042025625, 6.155395104202553, 6.155395104202621, 6.1553951041923405]\n",
- "2 [-0.44714894632536706, 6.345981429349622, -3.665937559877882, 0.9754545556627885] [3.788888888903877, 3.7888888888967944, 3.788888888900691, 3.788888888885915]\n"
+ "[1.6129032258064515, 1.032258064516129, 0.967741935483871, 0.967741935483871] [0.3848271439473079, 0.05597028203371821]\n"
]
}
],
"source": [
- "options = {'num_reads':20, 'iterations':3, 'num_qbits':5, \n",
- " 'encoding': RangedEfficientEncoding, 'range':10.0, 'offset':0.0,\n",
- " 'sampler':dimod.ExactSolver(),}\n",
- "qubols= AEQUBOLS(options)\n",
- "sol_num = qubols.solve(A, b)"
+ "# create the bqm\n",
+ "bqm = qubo.create_bqm(matrices, strength=1000)\n",
+ "\n",
+ "# add constraint\n",
+ "slacks2 = bqm.add_linear_inequality_constraint(qubo.all_expr[3], lagrange_multiplier=1, label=\"head2\", lb=1, ub=2)\n",
+ "slacks1 = bqm.add_linear_inequality_constraint(qubo.all_expr[2], lagrange_multiplier=1, label=\"head1\", lb=1, ub=2)\n",
+ "\n",
+ "# sample\n",
+ "sampleset = qubo.sample_bqm(bqm, num_reads=100000)\n",
+ "\n",
+ "# decode\n",
+ "sol, param = qubo.decode_solution(sampleset.lowest())\n",
+ "print(sol, param)"
]
},
{
"cell_type": "code",
- "execution_count": 46,
+ "execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
- ""
+ "array([-0.08064516, -0.03225806, 0.03114687, -0.05963951])"
]
},
- "execution_count": 46,
+ "execution_count": 9,
"metadata": {},
"output_type": "execute_result"
- },
- {
- "data": {
- "image/png": "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/c///I/+5V/+peXx5cuXNW3aNL377rsaNWqUPyOGhda+z9LNkZAJEyZo+PDheu2112S1hsTgWtCKiYnR8OHDtXXrVs2bN0/Szb/tbN26VT/84Q/NDRdmDMPQj370IxUXF2v79u3Kzc01O1LYmTRpko4cOXLLsUWLFql///76+c9/TglpJ2PHjv3GpeenTp1S9+7dTUp0f0KiiLRWt27dbnmcmJgoSerVqxd/42lHpaWlGj9+vLp3767f/va3qqysbPk1/vZ+/55//nl9+9vfVkFBgUaOHKnf/e53qq2t1aJFi8yOFlaWLFmiv/zlL1q7dq2SkpJa1uDY7XbFx8ebnC48JCUlfWPNTYcOHZSWlsZanHb005/+VGPGjNGvf/1rPfHEE9q7d69efvnlkBuhDqsigsDYvHmzzpw5ozNnznyj4BnczPm+fetb31JlZaV++ctfqqysTPn5+dq4ceM3FrDiwbz00kuSpPHjx99y/LXXXrvn1CQQTEaMGKHi4mItXbpUv/rVr5Sbm6vf/e53evLJJ82O1iYWg08OAABgEib2AQCAaSgiAADANBQRAABgGooIAAAwDUUEAACYhiICAABMQxEBAACmoYgAAADTUEQAAIBpKCIAAMA0FBEAAGAaiggAADDN/w/aAjiCdYLDtwAAAABJRU5ErkJggg==",
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
}
],
"source": [
- "import matplotlib.pyplot as plt\n",
- "plt.scatter(npsol, sol_num)\n",
- "plt.axline( (0,0),slope=1,linestyle='--',color='gray')"
+ "parameters = param\n",
+ "nlfunc(sol)"
]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
}
],
"metadata": {
diff --git a/example/qubo_poly.ipynb b/example/qubo_poly.ipynb
new file mode 100644
index 0000000..3451ee9
--- /dev/null
+++ b/example/qubo_poly.ipynb
@@ -0,0 +1,1150 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "tags": [
+ "remove_cell"
+ ]
+ },
+ "source": [
+ "# QUBO formulation of polynomial equation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sympy.matrices import Matrix, SparseMatrix"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Use case\n",
+ "\n",
+ "To illustrate the metohod we are taking the equation of the two node water system that reads:\n",
+ "\n",
+ "$$\n",
+ " 1/2 - x_0 + x_1 = 0 \\\\\n",
+ " 1 - x_1 = 0 \\\\\n",
+ " 3 - x_0^2 - x_2 = 0 \\\\\n",
+ " -1/2 x_1^2 + x_2 - x_3 = 0 \n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "\n",
+ "def nlfunc(input):\n",
+ " x0,x1,x2,x3 = input\n",
+ "\n",
+ " def f0():\n",
+ " return 1/2 - x0 + x1\n",
+ " \n",
+ " def f1():\n",
+ " return 1 - x1\n",
+ " \n",
+ " def f2():\n",
+ " return 3 - x0**2 - x2\n",
+ "\n",
+ " def f3():\n",
+ " return - 0.5*x1**2 + x2 - x3\n",
+ " \n",
+ " return np.array([f0(), f1(), f2(), f3()])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Classical Solution\n",
+ "\n",
+ "The solution of such a small system can be obtained by newton raphson"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/nico/QuantumApplicationLab/QuantumNewtonRaphson/quantum_newton_raphson/utils.py:74: SparseEfficiencyWarning: spsolve requires A be CSC or CSR matrix format\n",
+ " warn(\"spsolve requires A be CSC or CSR matrix format\", SparseEfficiencyWarning)\n"
+ ]
+ }
+ ],
+ "source": [
+ "from quantum_newton_raphson.newton_raphson import newton_raphson\n",
+ "\n",
+ "initial_point = np.random.rand(4)\n",
+ "res = newton_raphson(nlfunc, initial_point)\n",
+ "assert np.allclose(nlfunc(res.solution), 0)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([1.5 , 1. , 0.75, 0.25])"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ref_sol = res.solution\n",
+ "ref_sol"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Polynomial equation\n",
+ "\n",
+ "We first write the polynomial equation as follow (https://www.nature.com/articles/s41598-019-46729-0) \n",
+ "\n",
+ "$$\n",
+ "F(X) = 0\n",
+ "$$\n",
+ "\n",
+ "with\n",
+ "\n",
+ "$$\n",
+ "F_i = P_i^{(0)} + \\sum_j P_{ij}^{(1)}x_j + \\sum_{jk} P_{ijk}^{(2)}x_j x_k + \\sum_{jkl} P_{ijkl}^{(3)}x_j x_k x_l = 0\n",
+ "$$\n",
+ "\n",
+ "To solve the system we minimize the residual sum of square\n",
+ "\n",
+ "$$\n",
+ "\\chi^2 = [P^{(0)} + P^{(1)} X + P^{(2)} X X.T + P^{(3)} X X X ]^2\n",
+ "$$\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 53,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import sparse\n",
+ "def define_matrices():\n",
+ " \n",
+ " # system of equations\n",
+ " num_equations = 4\n",
+ " num_variables = 4\n",
+ "\n",
+ " weight_quadratic_eq = 0.1\n",
+ "\n",
+ " P0 = np.zeros(num_equations)\n",
+ " P0[0] = 1/2\n",
+ " P0[1] = 1\n",
+ " P0[2] = 3*weight_quadratic_eq\n",
+ " P0[3] = 0*weight_quadratic_eq\n",
+ "\n",
+ " P1 = np.zeros((num_equations, num_variables))\n",
+ " P1[0, 0] = -1\n",
+ " P1[0, 1] = 1\n",
+ "\n",
+ " P1[1, 1] = -1\n",
+ "\n",
+ " P1[2, 2] = -1*weight_quadratic_eq\n",
+ "\n",
+ " P1[3, 2] = 1 *weight_quadratic_eq\n",
+ " P1[3, 3] = -1*weight_quadratic_eq\n",
+ " \n",
+ "\n",
+ " P2 = np.zeros((num_equations, num_variables, num_variables))\n",
+ " P2[2, 0, 0] = -1*weight_quadratic_eq\n",
+ " P2[3, 1, 1] = -1/2*weight_quadratic_eq\n",
+ "\n",
+ " # P3 = np.zeros((num_equations, num_variables, num_variables, num_variables))\n",
+ " # P3[2,2,2,2] = -1\n",
+ "\n",
+ "\n",
+ " return sparse.COO(P0), sparse.COO(P1), sparse.COO(P2) #, sparse.COO(P3)\n",
+ "\n",
+ "matrices = define_matrices()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## 3. Solving the system\n",
+ "\n",
+ "We will use here the `SimulatedAnnealingSampler` to be able to run that code locally. Quantum solvers are available through the Leap cloud service."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 54,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from qubols.qubo_poly import QUBO_POLY\n",
+ "from qubols.qubo_poly_mixed_variables import QUBO_POLY_MIXED\n",
+ "from qubols.encodings import PositiveQbitEncoding, RangedEfficientEncoding\n",
+ "from qubols.solution_vector import SolutionVector_V2 as SolutionVector\n",
+ "from qubols.mixed_solution_vector import MixedSolutionVector_V2 as MixedSolutionVector\n",
+ "\n",
+ "from dwave.samplers import SimulatedAnnealingSampler\n",
+ "from dwave.samplers import SteepestDescentSolver\n",
+ "from dwave.samplers import TabuSampler\n",
+ "from dimod import ExactSolver\n",
+ "\n",
+ "nqbit = 5\n",
+ "step = 2/(2**nqbit-1)\n",
+ "encoding1 = PositiveQbitEncoding(nqbit = nqbit, step=step, offset=0, var_base_name='x')\n",
+ "# encoding1 = RangedEfficientEncoding(nqbit=nqbit, range=5, offset=5, var_base_name='x')\n",
+ "sol_vec1 = SolutionVector(2, encoding=encoding1)\n",
+ "\n",
+ "nqbit = 5\n",
+ "step = 2/(2**nqbit-1)\n",
+ "encoding2 = PositiveQbitEncoding(nqbit = nqbit, step=step, offset=0, var_base_name='x')\n",
+ "# encoding2 = RangedEfficientEncoding(nqbit=nqbit, range=5, offset=5, var_base_name='x')\n",
+ "sol_vec2 = SolutionVector(2, encoding=encoding2)\n",
+ "\n",
+ "sol_vec = MixedSolutionVector([sol_vec1,sol_vec2])\n",
+ "\n",
+ "sampler = SimulatedAnnealingSampler()\n",
+ "\n",
+ "options = {'num_reads':1000, 'sampler':sampler}\n",
+ "qubo = QUBO_POLY_MIXED(sol_vec, options)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 55,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([0. , 0.065, 0.129, 0.194, 0.258, 0.323, 0.387, 0.452, 0.516,\n",
+ " 0.581, 0.645, 0.71 , 0.774, 0.839, 0.903, 0.968, 1.032, 1.097,\n",
+ " 1.161, 1.226, 1.29 , 1.355, 1.419, 1.484, 1.548, 1.613, 1.677,\n",
+ " 1.742, 1.806, 1.871, 1.935, 2. ])"
+ ]
+ },
+ "execution_count": 55,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "np.sort(encoding1.get_possible_values())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 56,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "prec: 0.06451612903225806 0.06451612903225806\n",
+ "\n",
+ "\n",
+ "ref : [1.5 1. 0.75 0.25]\n",
+ "sol : [1.484 0.968 0.839 0.387]\n",
+ "diff: [ 0.016 0.032 -0.089 -0.137]\n",
+ "\n",
+ "\n",
+ "encoded_ref: [1.484 1.032 0.774 0.258]\n",
+ "encoded_sol: [1.484 0.968 0.839 0.387]\n",
+ "diff : [ 0. 0.065 -0.065 -0.129]\n",
+ "\n",
+ "\n",
+ "eref: -1.3366096060604533\n",
+ "esol: -1.3386800300201653\n",
+ "\n",
+ "\n",
+ "res_ref: 0.06505306758847451\n",
+ "res_sol: 0.05678808027274856\n"
+ ]
+ }
+ ],
+ "source": [
+ "matrices = tuple(sparse.COO(m) for m in matrices)\n",
+ "\n",
+ "bqm = qubo.create_bqm(matrices, strength=10000)\n",
+ "\n",
+ "# sample\n",
+ "sampleset = qubo.sample_bqm(bqm, num_reads=10000)\n",
+ "\n",
+ "# decode\n",
+ "qubo.verify_quadratic_constraints(sampleset.lowest())\n",
+ "sol = qubo.decode_solution(sampleset.lowest().record[0][0])\n",
+ "sol = np.array(sol).reshape(-1)\n",
+ "\n",
+ "data_ref, eref = qubo.compute_energy(ref_sol, bqm)\n",
+ "data_sol, esol = qubo.compute_energy(sol, bqm)\n",
+ "\n",
+ "\n",
+ "np.set_printoptions(precision=3)\n",
+ "\n",
+ "print('prec: ', encoding1.get_average_precision(), encoding2.get_average_precision())\n",
+ "print('\\n')\n",
+ "\n",
+ "print('ref : ', np.array(ref_sol)) \n",
+ "print('sol : ', sol)\n",
+ "print('diff: ', ref_sol - sol)\n",
+ "print('\\n')\n",
+ "\n",
+ "print('encoded_ref: ', np.array(data_ref[0]))\n",
+ "print('encoded_sol: ', np.array(data_sol[0]))\n",
+ "print('diff : ', np.array(data_ref[0]) - np.array(data_sol[0]))\n",
+ "print('\\n')\n",
+ "print('eref: ', eref)\n",
+ "print('esol: ', esol)\n",
+ "print('\\n')\n",
+ "print('res_ref: ', np.linalg.norm(nlfunc(data_ref[0])))\n",
+ "print('res_sol: ', np.linalg.norm(nlfunc(data_sol[0])))\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3.8.0 ('qubols')",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.0"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "390591a6667b05d6f83558ed597f55be1305d4de992db830679d199a6a0e520c"
+ }
+ },
+ "widgets": {
+ "application/vnd.jupyter.widget-state+json": {
+ "state": {
+ "17046f96803d48aa8c63b99a5c89e6f3": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "1a46e33438a648dd839fe5fd43b9582b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "1f812fe9a02b41b885f01e3190957acf": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": "\n \". . . . right \"\n ",
+ "grid_template_columns": "20% 20% 20% 20% 20%",
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "100%"
+ }
+ },
+ "20439ee3a84741dc9a137f7964898fc3": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_f0e6a746eff140269e915ef65de640c7",
+ "placeholder": "",
+ "style": "IPY_MODEL_96316857896d44328b3898d849594ae7",
+ "value": "Status
"
+ }
+ },
+ "246d39f98fdb4892bc1d5bfb88d2f1cd": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "27e0478b2a9c4533b2e67eac937cbebc": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HBoxModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_ac5a0f78ef8140a2abdf035fd1751936",
+ "IPY_MODEL_5ff6f36eaa894a339210fc29fdbeedcf",
+ "IPY_MODEL_20439ee3a84741dc9a137f7964898fc3",
+ "IPY_MODEL_eef64edafd8f47c885da65fa3ca0ab8a",
+ "IPY_MODEL_a38db3ffdfc848c0b0150e42b3509be5"
+ ],
+ "layout": "IPY_MODEL_fc018f99fbb44aa9beb54a8e6be5209e"
+ }
+ },
+ "2f981df37e914685992f4564103ef872": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "3aa67247d1a9433f87b13ce1370c8b1c": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "190px"
+ }
+ },
+ "40a8f99fef5b4aad89f533edcb091c3f": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "ButtonStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "ButtonStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "button_color": null,
+ "font_weight": ""
+ }
+ },
+ "46f75da5f7ab4f33b4df8618ccffde6b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "5ff6f36eaa894a339210fc29fdbeedcf": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_9e036ff6f31e4efb9471d371db06f533",
+ "placeholder": "",
+ "style": "IPY_MODEL_1a46e33438a648dd839fe5fd43b9582b",
+ "value": "Backend
"
+ }
+ },
+ "608e06da96f840e890006ad286afc34b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_74038cd5fbe8491ba5457f6cc81f7b5a",
+ "placeholder": "",
+ "style": "IPY_MODEL_8569084253df4279b752a85c0b99027b",
+ "value": "Circuit Properties
"
+ }
+ },
+ "74038cd5fbe8491ba5457f6cc81f7b5a": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": "0px 0px 10px 0px",
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "8569084253df4279b752a85c0b99027b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "917c693fd8d84f2e99f59d75cd5062c2": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "GridBoxModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "GridBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "GridBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_b7e87c3bbc404502ab1550d64f86c473"
+ ],
+ "layout": "IPY_MODEL_1f812fe9a02b41b885f01e3190957acf"
+ }
+ },
+ "96316857896d44328b3898d849594ae7": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "9e036ff6f31e4efb9471d371db06f533": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "145px"
+ }
+ },
+ "a38db3ffdfc848c0b0150e42b3509be5": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_2f981df37e914685992f4564103ef872",
+ "placeholder": "",
+ "style": "IPY_MODEL_246d39f98fdb4892bc1d5bfb88d2f1cd",
+ "value": "Message
"
+ }
+ },
+ "ac5a0f78ef8140a2abdf035fd1751936": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_3aa67247d1a9433f87b13ce1370c8b1c",
+ "placeholder": "",
+ "style": "IPY_MODEL_46f75da5f7ab4f33b4df8618ccffde6b",
+ "value": "Job ID
"
+ }
+ },
+ "b7e87c3bbc404502ab1550d64f86c473": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "ButtonModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "ButtonModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "ButtonView",
+ "button_style": "primary",
+ "description": "Clear",
+ "disabled": false,
+ "icon": "",
+ "layout": "IPY_MODEL_f6a39516121743099bece32bc0c3c696",
+ "style": "IPY_MODEL_40a8f99fef5b4aad89f533edcb091c3f",
+ "tooltip": ""
+ }
+ },
+ "eef64edafd8f47c885da65fa3ca0ab8a": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_ef270ca07615429ab689824b66fdb1ff",
+ "placeholder": "",
+ "style": "IPY_MODEL_17046f96803d48aa8c63b99a5c89e6f3",
+ "value": "Queue
"
+ }
+ },
+ "ef270ca07615429ab689824b66fdb1ff": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "70px"
+ }
+ },
+ "f0e6a746eff140269e915ef65de640c7": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "95px"
+ }
+ },
+ "f6a39516121743099bece32bc0c3c696": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": "right",
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": "0px 0px 0px 0px",
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "70px"
+ }
+ },
+ "fc018f99fbb44aa9beb54a8e6be5209e": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": "0px 0px 0px 37px",
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "600px"
+ }
+ }
+ },
+ "version_major": 2,
+ "version_minor": 0
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/example/qubo_poly_landscape.ipynb b/example/qubo_poly_landscape.ipynb
new file mode 100644
index 0000000..4f79f57
--- /dev/null
+++ b/example/qubo_poly_landscape.ipynb
@@ -0,0 +1,1294 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "tags": [
+ "remove_cell"
+ ]
+ },
+ "source": [
+ "# QUBO formulation of polynomial equation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sympy.matrices import Matrix, SparseMatrix"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Use case\n",
+ "\n",
+ "To illustrate the metohod we are taking the equation of the two node water system that reads:\n",
+ "\n",
+ "$$\n",
+ "x_0^2 + x_1 - 3 = 0 \\\\\n",
+ "x_0 x_1 - 2 x_1^2 -1 = 0 \n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "\n",
+ "def nlfunc(input):\n",
+ " x0,x1 = input\n",
+ "\n",
+ " def f0():\n",
+ " return 2*x0**2 + 3*x0*x1 + x1**2 + 2*x0 + 4*x1 - 51\n",
+ " \n",
+ " def f1():\n",
+ " return x0**2 + 2*x0*x1 + 2*x1**2 + 3*x0 + 2*x1 - 46\n",
+ " \n",
+ " \n",
+ " return np.array([f0(), f1()])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Classical Solution\n",
+ "\n",
+ "The solution of such a small system can be obtained by newton raphson"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from quantum_newton_raphson.newton_raphson import newton_raphson\n",
+ "\n",
+ "initial_point = np.random.rand(2)\n",
+ "res = newton_raphson(nlfunc, initial_point)\n",
+ "assert np.allclose(nlfunc(res.solution), 0)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([2., 3.])"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ref_sol = res.solution\n",
+ "ref_sol"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Polynomial equation\n",
+ "\n",
+ "We first write the polynomial equation as follow (https://www.nature.com/articles/s41598-019-46729-0) "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import sparse\n",
+ "def define_matrices():\n",
+ " \n",
+ " # system of equations\n",
+ " num_equations = 2\n",
+ " num_variables = 2\n",
+ "\n",
+ " P0 = np.zeros((num_equations,1))\n",
+ " P0[0] = -51\n",
+ " P0[1] = -46\n",
+ "\n",
+ " P1 = np.zeros((num_equations, num_variables))\n",
+ " P1[0, 0] = 2\n",
+ " P1[0, 1] = 4\n",
+ " P1[1, 0] = 3\n",
+ " P1[1, 1] = 2\n",
+ "\n",
+ "\n",
+ " P2 = np.zeros((num_equations, num_variables, num_variables))\n",
+ " P2[0, 0, 0] = 2\n",
+ " P2[0, 0, 1] = 3\n",
+ " P2[0, 1, 1] = 1\n",
+ "\n",
+ " P2[1, 0, 0] = 1\n",
+ " P2[1, 0, 1] = 2\n",
+ " P2[1, 1, 1] = 2\n",
+ "\n",
+ " return P0, P1, P2 #, sparse.COO(P3)\n",
+ "\n",
+ "matrices = define_matrices()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[0.],\n",
+ " [0.]])"
+ ]
+ },
+ "execution_count": 20,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "def verify_solution(x, matrices):\n",
+ " \"\"\"generates the classical solution.\"\"\"\n",
+ "\n",
+ " P0, P1, P2 = matrices\n",
+ " x = np.array([2,3]).reshape(-1,1)\n",
+ " x2 = x@x.T\n",
+ " return P0 + P1@x + [ [(P2[0] * x2).sum()], [(P2[1] * x2).sum()] ]\n",
+ "\n",
+ "verify_solution(np.array([2.,3]), matrices)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## 3. Solving the system\n",
+ "\n",
+ "We will use here the `SimulatedAnnealingSampler` to be able to run that code locally. Quantum solvers are available through the Leap cloud service."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 65,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from qubols.qubo_poly import QUBO_POLY\n",
+ "from qubols.qubo_poly_mixed_variables import QUBO_POLY_MIXED\n",
+ "from qubols.encodings import PositiveQbitEncoding, RangedEfficientEncoding\n",
+ "from qubols.solution_vector import SolutionVector_V2 as SolutionVector\n",
+ "\n",
+ "from dwave.samplers import SimulatedAnnealingSampler\n",
+ "from dwave.samplers import SteepestDescentSolver\n",
+ "from dwave.samplers import TabuSampler\n",
+ "from dimod import ExactSolver\n",
+ "\n",
+ "nqbit = 7\n",
+ "step = 6/(2**nqbit-1)\n",
+ "step = 0.17\n",
+ "# encoding = PositiveQbitEncoding(nqbit = nqbit, step=step, offset=0.0, var_base_name='x')\n",
+ "encoding = RangedEfficientEncoding(nqbit=nqbit, range=3, offset=3, var_base_name='x')\n",
+ "sol_vec = SolutionVector(2, encoding=encoding)\n",
+ "sampler = SimulatedAnnealingSampler()\n",
+ "# sampler = TabuSampler()\n",
+ "\n",
+ "options = {'num_reads':1000, 'sampler':sampler}\n",
+ "qubo = QUBO_POLY(sol_vec, options)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 66,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([-4.762e-02, 1.665e-16, 4.762e-02, 9.524e-02, 1.429e-01,\n",
+ " 1.905e-01, 2.381e-01, 2.857e-01, 3.333e-01, 3.810e-01,\n",
+ " 4.286e-01, 4.762e-01, 5.238e-01, 5.714e-01, 6.190e-01,\n",
+ " 6.667e-01, 7.143e-01, 7.619e-01, 8.095e-01, 8.571e-01,\n",
+ " 9.048e-01, 9.524e-01, 1.000e+00, 1.048e+00, 1.095e+00,\n",
+ " 1.143e+00, 1.190e+00, 1.238e+00, 1.286e+00, 1.333e+00,\n",
+ " 1.381e+00, 1.429e+00, 1.476e+00, 1.524e+00, 1.571e+00,\n",
+ " 1.619e+00, 1.667e+00, 1.714e+00, 1.762e+00, 1.810e+00,\n",
+ " 1.857e+00, 1.905e+00, 1.952e+00, 2.000e+00, 2.048e+00,\n",
+ " 2.095e+00, 2.143e+00, 2.190e+00, 2.238e+00, 2.286e+00,\n",
+ " 2.333e+00, 2.381e+00, 2.429e+00, 2.476e+00, 2.524e+00,\n",
+ " 2.571e+00, 2.619e+00, 2.667e+00, 2.714e+00, 2.762e+00,\n",
+ " 2.810e+00, 2.857e+00, 2.905e+00, 2.952e+00, 3.000e+00,\n",
+ " 3.048e+00, 3.095e+00, 3.143e+00, 3.190e+00, 3.238e+00,\n",
+ " 3.286e+00, 3.333e+00, 3.381e+00, 3.429e+00, 3.476e+00,\n",
+ " 3.524e+00, 3.571e+00, 3.619e+00, 3.667e+00, 3.714e+00,\n",
+ " 3.762e+00, 3.810e+00, 3.857e+00, 3.905e+00, 3.952e+00,\n",
+ " 4.000e+00, 4.048e+00, 4.095e+00, 4.143e+00, 4.190e+00,\n",
+ " 4.238e+00, 4.286e+00, 4.333e+00, 4.381e+00, 4.429e+00,\n",
+ " 4.476e+00, 4.524e+00, 4.571e+00, 4.619e+00, 4.667e+00,\n",
+ " 4.714e+00, 4.762e+00, 4.810e+00, 4.857e+00, 4.905e+00,\n",
+ " 4.952e+00, 5.000e+00, 5.048e+00, 5.095e+00, 5.143e+00,\n",
+ " 5.190e+00, 5.238e+00, 5.286e+00, 5.333e+00, 5.381e+00,\n",
+ " 5.429e+00, 5.476e+00, 5.524e+00, 5.571e+00, 5.619e+00,\n",
+ " 5.667e+00, 5.714e+00, 5.762e+00, 5.810e+00, 5.857e+00,\n",
+ " 5.905e+00, 5.952e+00, 6.000e+00])"
+ ]
+ },
+ "execution_count": 66,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "np.sort(encoding.get_possible_values())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 68,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "prec: -0.00037495313085861336\n",
+ "\n",
+ "\n",
+ "ref : [2 3]\n",
+ "sol : [2.048 2.952]\n",
+ "diff: [-0.048 0.048]\n",
+ "\n",
+ "\n",
+ "encoded_ref: [2. 3.]\n",
+ "encoded_sol: [2.048 2.952]\n",
+ "diff : [-0.048 0.048]\n",
+ "\n",
+ "\n",
+ "eref: -637.0\n",
+ "esol: -636.923977107051\n",
+ "\n",
+ "\n",
+ "res_ref: 0.0\n",
+ "res_sol: 0.27572241577578777\n"
+ ]
+ }
+ ],
+ "source": [
+ "matrices = tuple(sparse.COO(m) for m in matrices)\n",
+ "\n",
+ "bqm = qubo.create_bqm(matrices, strength=1E6)\n",
+ "\n",
+ "# sample\n",
+ "sampleset = qubo.sample_bqm(bqm, num_reads=10000)\n",
+ "\n",
+ "# decode\n",
+ "sol = qubo.decode_solution(sampleset.lowest().record[0][0])\n",
+ "sol = np.array(sol).reshape(-1)\n",
+ "elowest = sampleset.lowest().record[0][1]\n",
+ "\n",
+ "ref_sol = [2, 3]\n",
+ "data_ref, eref = qubo.compute_energy(ref_sol, bqm)\n",
+ "data_sol, esol = qubo.compute_energy(sol, bqm)\n",
+ "\n",
+ "np.set_printoptions(precision=3)\n",
+ "\n",
+ "print('prec: ', encoding.get_average_precision())\n",
+ "print('\\n')\n",
+ "\n",
+ "print('ref : ', np.array(ref_sol)) \n",
+ "print('sol : ', sol)\n",
+ "print('diff: ', ref_sol - sol)\n",
+ "print('\\n')\n",
+ "\n",
+ "print('encoded_ref: ', np.array(data_ref[0]))\n",
+ "print('encoded_sol: ', np.array(data_sol[0]))\n",
+ "print('diff : ', np.array(data_ref[0]) - np.array(data_sol[0]))\n",
+ "print('\\n')\n",
+ "print('eref: ', eref)\n",
+ "print('esol: ', esol)\n",
+ "print('\\n')\n",
+ "print('res_ref: ', np.linalg.norm(nlfunc(data_ref[0])))\n",
+ "print('res_sol: ', np.linalg.norm(nlfunc(data_sol[0])))\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "vals = encoding.get_possible_values()\n",
+ "nvals = len(vals)\n",
+ "energies = np.zeros((nvals,nvals))\n",
+ "residues = np.zeros((nvals,nvals))\n",
+ "for i1, v1 in enumerate(vals):\n",
+ " for i2, v2 in enumerate(vals):\n",
+ " data_ref, energy = qubo.compute_energy([v1,v2], bqm)\n",
+ " energies[i1,i2] = energy\n",
+ " residues[i1, i2] = np.linalg.norm(nlfunc(data_ref[0]))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 45,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import matplotlib.pyplot as plt \n",
+ "plt.imshow(residues)\n",
+ "plt.colorbar()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 57,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[]"
+ ]
+ },
+ "execution_count": 57,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fig, ax1 = plt.subplots()\n",
+ "ax2 = ax1.twinx() \n",
+ "idx = 11\n",
+ "ax1.plot(energies[idx,15:20])\n",
+ "ax2.plot(residues[idx, 15:20])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 59,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[]"
+ ]
+ },
+ "execution_count": 59,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fig, ax1 = plt.subplots()\n",
+ "ax2 = ax1.twinx() \n",
+ "idx = 18\n",
+ "ax1.plot(energies[10:15,18])\n",
+ "ax2.plot(residues[10:15, 18])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "ref: [2, 3] -> [2.0, 3.0] energy: -636.9999999990687\n",
+ "sol: [5.16, 1.33] -> [5.2, 1.4] energy: 1522.8207999998704\n",
+ "[-3.16 1.67]\n"
+ ]
+ }
+ ],
+ "source": [
+ "ref_sol = [2, 3]\n",
+ "trial_sol = [5.16, 1.33]\n",
+ "data_ref, eref = qubo.compute_energy(ref_sol, bqm)\n",
+ "data_sol, esol = qubo.compute_energy(trial_sol, bqm)\n",
+ "\n",
+ "print('ref: ', ref_sol, '->', data_ref[0], ' energy: ', eref)\n",
+ "print('sol: ', trial_sol, '->', data_sol[0], ' energy: ', esol)\n",
+ "print(np.array(ref_sol) - np.array(trial_sol))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "-636.9999999031425"
+ ]
+ },
+ "execution_count": 28,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sampleset.lowest().record[0][1]"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3.8.0 ('qubols')",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.0"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "390591a6667b05d6f83558ed597f55be1305d4de992db830679d199a6a0e520c"
+ }
+ },
+ "widgets": {
+ "application/vnd.jupyter.widget-state+json": {
+ "state": {
+ "17046f96803d48aa8c63b99a5c89e6f3": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "1a46e33438a648dd839fe5fd43b9582b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "1f812fe9a02b41b885f01e3190957acf": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": "\n \". . . . right \"\n ",
+ "grid_template_columns": "20% 20% 20% 20% 20%",
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "100%"
+ }
+ },
+ "20439ee3a84741dc9a137f7964898fc3": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_f0e6a746eff140269e915ef65de640c7",
+ "placeholder": "",
+ "style": "IPY_MODEL_96316857896d44328b3898d849594ae7",
+ "value": "Status
"
+ }
+ },
+ "246d39f98fdb4892bc1d5bfb88d2f1cd": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "27e0478b2a9c4533b2e67eac937cbebc": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HBoxModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_ac5a0f78ef8140a2abdf035fd1751936",
+ "IPY_MODEL_5ff6f36eaa894a339210fc29fdbeedcf",
+ "IPY_MODEL_20439ee3a84741dc9a137f7964898fc3",
+ "IPY_MODEL_eef64edafd8f47c885da65fa3ca0ab8a",
+ "IPY_MODEL_a38db3ffdfc848c0b0150e42b3509be5"
+ ],
+ "layout": "IPY_MODEL_fc018f99fbb44aa9beb54a8e6be5209e"
+ }
+ },
+ "2f981df37e914685992f4564103ef872": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "3aa67247d1a9433f87b13ce1370c8b1c": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "190px"
+ }
+ },
+ "40a8f99fef5b4aad89f533edcb091c3f": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "ButtonStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "ButtonStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "button_color": null,
+ "font_weight": ""
+ }
+ },
+ "46f75da5f7ab4f33b4df8618ccffde6b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "5ff6f36eaa894a339210fc29fdbeedcf": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_9e036ff6f31e4efb9471d371db06f533",
+ "placeholder": "",
+ "style": "IPY_MODEL_1a46e33438a648dd839fe5fd43b9582b",
+ "value": "Backend
"
+ }
+ },
+ "608e06da96f840e890006ad286afc34b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_74038cd5fbe8491ba5457f6cc81f7b5a",
+ "placeholder": "",
+ "style": "IPY_MODEL_8569084253df4279b752a85c0b99027b",
+ "value": "Circuit Properties
"
+ }
+ },
+ "74038cd5fbe8491ba5457f6cc81f7b5a": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": "0px 0px 10px 0px",
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "8569084253df4279b752a85c0b99027b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "917c693fd8d84f2e99f59d75cd5062c2": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "GridBoxModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "GridBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "GridBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_b7e87c3bbc404502ab1550d64f86c473"
+ ],
+ "layout": "IPY_MODEL_1f812fe9a02b41b885f01e3190957acf"
+ }
+ },
+ "96316857896d44328b3898d849594ae7": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "9e036ff6f31e4efb9471d371db06f533": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "145px"
+ }
+ },
+ "a38db3ffdfc848c0b0150e42b3509be5": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_2f981df37e914685992f4564103ef872",
+ "placeholder": "",
+ "style": "IPY_MODEL_246d39f98fdb4892bc1d5bfb88d2f1cd",
+ "value": "Message
"
+ }
+ },
+ "ac5a0f78ef8140a2abdf035fd1751936": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_3aa67247d1a9433f87b13ce1370c8b1c",
+ "placeholder": "",
+ "style": "IPY_MODEL_46f75da5f7ab4f33b4df8618ccffde6b",
+ "value": "Job ID
"
+ }
+ },
+ "b7e87c3bbc404502ab1550d64f86c473": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "ButtonModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "ButtonModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "ButtonView",
+ "button_style": "primary",
+ "description": "Clear",
+ "disabled": false,
+ "icon": "",
+ "layout": "IPY_MODEL_f6a39516121743099bece32bc0c3c696",
+ "style": "IPY_MODEL_40a8f99fef5b4aad89f533edcb091c3f",
+ "tooltip": ""
+ }
+ },
+ "eef64edafd8f47c885da65fa3ca0ab8a": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_ef270ca07615429ab689824b66fdb1ff",
+ "placeholder": "",
+ "style": "IPY_MODEL_17046f96803d48aa8c63b99a5c89e6f3",
+ "value": "Queue
"
+ }
+ },
+ "ef270ca07615429ab689824b66fdb1ff": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "70px"
+ }
+ },
+ "f0e6a746eff140269e915ef65de640c7": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "95px"
+ }
+ },
+ "f6a39516121743099bece32bc0c3c696": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": "right",
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": "0px 0px 0px 0px",
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "70px"
+ }
+ },
+ "fc018f99fbb44aa9beb54a8e6be5209e": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": "0px 0px 0px 37px",
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "600px"
+ }
+ }
+ },
+ "version_major": 2,
+ "version_minor": 0
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/example/qubo_poly_mixed.ipynb b/example/qubo_poly_mixed.ipynb
new file mode 100644
index 0000000..7271560
--- /dev/null
+++ b/example/qubo_poly_mixed.ipynb
@@ -0,0 +1,1238 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "tags": [
+ "remove_cell"
+ ]
+ },
+ "source": [
+ "# QUBO formulation of polynomial equation"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Use case\n",
+ "\n",
+ "To illustrate the metohod we are taking the equation of the two node water system that reads:\n",
+ "\n",
+ "$$\n",
+ "-1 - x_0 + x_1 = 0 \\\\\n",
+ " 1 - x_1 = 0 \\\\\n",
+ " 2 - q x_0^2 - x_2 = 0 \\\\\n",
+ " -p x_1^2 + x_2 - x_3 = 0 \n",
+ "$$\n",
+ "\n",
+ "with $q$ and $p$ paramerers taking disrete values either 1 or 2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "\n",
+ "def nlfunc(input):\n",
+ " x0,x1,x2,x3 = input\n",
+ " q, p = parameters\n",
+ "\n",
+ " def f0():\n",
+ " return -1 - x0 + x1\n",
+ " \n",
+ " def f1():\n",
+ " return 1 - x1\n",
+ " \n",
+ " def f2():\n",
+ " return 2 - q*x0**2 - x2\n",
+ "\n",
+ " def f3():\n",
+ " return -p*x1**2 + x2 - x3\n",
+ " \n",
+ " return np.array([f0(), f1(), f2(), f3()])\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Classical Solution\n",
+ "\n",
+ "The solution of such a small system can be obtained by newton raphson"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[0, 0] [1.97361016e-11 1.00000000e+00 2.00000000e+00 2.00000000e+00]\n",
+ "[0, 1] [2.3854661e-21 1.0000000e+00 2.0000000e+00 1.0000000e+00]\n",
+ "[0, 2] [ 2.77586915e-17 1.00000000e+00 2.00000000e+00 -2.38723485e-11]\n",
+ "[0, 3] [-4.6259067e-17 1.0000000e+00 2.0000000e+00 -1.0000000e+00]\n",
+ "[1, 0] [8.32667906e-17 1.00000000e+00 2.00000000e+00 2.00000000e+00]\n",
+ "[1, 1] [1.11021173e-16 1.00000000e+00 2.00000000e+00 1.00000000e+00]\n",
+ "[1, 2] [-5.55113153e-17 1.00000000e+00 2.00000000e+00 2.11775042e-13]\n",
+ "[1, 3] [ 1.62400434e-22 1.00000000e+00 2.00000000e+00 -1.00000000e+00]\n",
+ "[2, 0] [-4.69045012e-21 1.00000000e+00 2.00000000e+00 2.00000000e+00]\n",
+ "[2, 1] [-1.01094061e-21 1.00000000e+00 2.00000000e+00 1.00000000e+00]\n",
+ "[2, 2] [5.55097881e-17 1.00000000e+00 2.00000000e+00 0.00000000e+00]\n",
+ "[2, 3] [-1.0004285e-21 1.0000000e+00 2.0000000e+00 -1.0000000e+00]\n",
+ "[3, 0] [-1.11021835e-16 1.00000000e+00 2.00000000e+00 2.00000000e+00]\n",
+ "[3, 1] [-8.32667269e-17 1.00000000e+00 2.00000000e+00 1.00000000e+00]\n",
+ "[3, 2] [ 5.55142848e-17 1.00000000e+00 2.00000000e+00 -5.16987883e-26]\n",
+ "[3, 3] [ 5.5509641e-17 1.0000000e+00 2.0000000e+00 -1.0000000e+00]\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/nico/QuantumApplicationLab/QuantumNewtonRaphson/quantum_newton_raphson/utils.py:74: SparseEfficiencyWarning: spsolve requires A be CSC or CSR matrix format\n",
+ " warn(\"spsolve requires A be CSC or CSR matrix format\", SparseEfficiencyWarning)\n"
+ ]
+ }
+ ],
+ "source": [
+ "from quantum_newton_raphson.newton_raphson import newton_raphson\n",
+ "\n",
+ "parameters_list = [[i, j] for i in range(4) for j in range(4)] \n",
+ "\n",
+ "for parameters in parameters_list:\n",
+ " initial_point = np.random.rand(4)\n",
+ " res = newton_raphson(nlfunc, initial_point)\n",
+ " assert np.allclose(nlfunc(res.solution), 0)\n",
+ " print(parameters, res.solution)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## 2. QUBO formalism for linear systems\n",
+ "\n",
+ "The Quandratic Unconstrainted Binary Optimization problem, or QUBO, allows to minimize the cost function :\n",
+ "\n",
+ "$$\n",
+ "E(x) = x^{T}Qx\n",
+ "$$\n",
+ "\n",
+ "where the variables $x_i$ are binaries, i.e. the are 0 or 1. The equation above can be rewritten as :\n",
+ "\n",
+ "$$\n",
+ "E(x) = \\sum_i Q_{ii}x_i + \\sum_{ij} Q_{ij}x_ix_j\n",
+ "$$\n",
+ "\n",
+ "that is very similar to the Ising model, basis of the quantum annealler architecture. \n",
+ "\n",
+ "### Encoding real numbers in binary variables\n",
+ "\n",
+ "In the QUBO problems, variables are binaries and we of course want to solve for real numbers in our case. There ar e different ways to encode real numbers in multiple binaries. In our case since the variables are between -1.0 and 1.0 we can use the following encoding : \n",
+ "\n",
+ "$$\n",
+ "r_i = a \\sum_n x_n 2^{n} - x_{k+n} 2^{n} \n",
+ "$$\n",
+ "\n",
+ "where $a$ is a normalization constant. THis encoding is created in the `SolutionVector` class that allows to encode/decode real numbers in a series of binaries variables. We use here the `RealUnitQbitEncoding` to obtain real numbers between -1 and 1. The number of qbit controls the precision of the reals we can obtain."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Polynomial equation\n",
+ "\n",
+ "We first write the polynomial equation as follow (https://www.nature.com/articles/s41598-019-46729-0) \n",
+ "\n",
+ "$$\n",
+ "F(X) = 0\n",
+ "$$\n",
+ "\n",
+ "with\n",
+ "\n",
+ "$$\n",
+ "F_i = P_i^{(0)} + \\sum_j P_{ij}^{(1)}x_j + \\sum_{jk} P_{ijk}^{(2)}x_j x_k = 0\n",
+ "$$\n",
+ "\n",
+ "To solve the system we minimize the residual sum of square\n",
+ "\n",
+ "$$\n",
+ "\\chi^2 = [P^{(0)} + P^{(1)} X + P^{(2)} X X.T ]^2\n",
+ "$$\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Use case\n",
+ "\n",
+ "To illustrate the metohod we are taking the equation of the two node water system that reads:\n",
+ "\n",
+ "$$\n",
+ "-1 - x_0 + x_1 = 0 \\\\\n",
+ " 1 - x_1 = 0 \\\\\n",
+ " 2 - q x_0^2 - x_2 = 0 \\\\\n",
+ " -p x_1^2 + x_2 - x_3 = 0 \\\\\n",
+ " c(q + p) \\rightarrow 0 \n",
+ "$$\n",
+ "\n",
+ "with $q$ and $p$ paramerers taking disrete values either 1 or 2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import sparse\n",
+ "def define_matrices():\n",
+ " \n",
+ " # system of equations\n",
+ " num_equations = 5\n",
+ " num_variables = 6\n",
+ "\n",
+ " P0 = np.zeros((num_equations,1))\n",
+ " P0[0] = -1\n",
+ " P0[1] = 1\n",
+ " P0[2] = 2\n",
+ " P0[3] = 0\n",
+ "\n",
+ " P1 = np.zeros((num_equations, num_variables))\n",
+ " P1[0, 0] = -1\n",
+ " P1[0, 1] = 1\n",
+ "\n",
+ " P1[1, 1] = -1\n",
+ "\n",
+ " P1[2, 2] = -1\n",
+ "\n",
+ " P1[3, 2] = 1 \n",
+ " P1[3, 3] = -1\n",
+ "\n",
+ " # cost\n",
+ " c = 1E-1\n",
+ " P1[4,4] = c\n",
+ " P1[4,5] = c\n",
+ " \n",
+ "\n",
+ " P2 = np.zeros((num_equations, num_variables, num_variables))\n",
+ "\n",
+ "\n",
+ " P3 = np.zeros((num_equations, num_variables, num_variables, num_variables))\n",
+ " P3[2, 0, 0, 4] = -1\n",
+ " P3[3, 1, 1, 5] = -1\n",
+ "\n",
+ "\n",
+ " return sparse.COO(P0), sparse.COO(P1), sparse.COO(P2), sparse.COO(P3)\n",
+ "\n",
+ "matrices = define_matrices()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## 3. Solving the system\n",
+ "\n",
+ "We will use here the `SimulatedAnnealingSampler` to be able to run that code locally. Quantum solvers are available through the Leap cloud service."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from qubols.qubo_poly import QUBO_POLY\n",
+ "from qubols.encodings import PositiveQbitEncoding\n",
+ "import dimod\n",
+ "# options = {'num_reads':20, 'num_qbits':2, 'sampler':dimod.ExactSolver(), \n",
+ "# 'encoding': PositiveQbitEncoding}\n",
+ "# qubols=QUBO_POLY(options)\n",
+ "# sol = qubols.solve(matrices)\n",
+ "# sol"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Switch sampler"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([0., 1., 2., 2., 0., 0.])"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import neal\n",
+ "sampler = neal.SimulatedAnnealingSampler()\n",
+ "options = {'num_reads':100, 'num_qbits':2, 'sampler':sampler, \n",
+ " 'encoding': PositiveQbitEncoding}\n",
+ "qubols=QUBO_POLY(options)\n",
+ "\n",
+ "sol = qubols.solve(matrices)\n",
+ "sol"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Add slack variables"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "bqm = qubols.create_qubo_matrix(qubols.x)\n",
+ "# slacks1 = bqm.add_linear_inequality_constraint([(\"x_003_001\",1), (\"x_003_002\",2)], lagrange_multiplier=2/3, label=\"head1\", lb=0, ub=1)\n",
+ "slacks2 = bqm.add_linear_inequality_constraint(qubols.all_expr[3], lagrange_multiplier=1, label=\"head2\", lb=0, ub=1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import neal\n",
+ "sampler = neal.SimulatedAnnealingSampler()\n",
+ "sampleset = sampler.sample(bqm, num_reads = 100)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([0., 1., 2., 1., 0., 1.])"
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sol = sampleset.lowest()\n",
+ "idx, vars, data = qubols.extract_data(sol)\n",
+ "sol = qubols.solution_vector.decode_solution(data)\n",
+ "sol"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([0., 0., 0., 0.])"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "parameters = sol[4:]\n",
+ "nlfunc(sol[:4])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['x_001_001',\n",
+ " 'x_001_002',\n",
+ " 'x_002_001',\n",
+ " 'x_002_002',\n",
+ " 'x_003_001',\n",
+ " 'x_003_002',\n",
+ " 'x_004_001',\n",
+ " 'x_004_002',\n",
+ " 'x_005_001',\n",
+ " 'x_005_002',\n",
+ " 'x_006_001',\n",
+ " 'x_006_002']"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "qubols.all_vars"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[[('x_001_001', 1), ('x_001_002', 2)],\n",
+ " [('x_002_001', 1), ('x_002_002', 2)],\n",
+ " [('x_003_001', 1), ('x_003_002', 2)],\n",
+ " [('x_004_001', 1), ('x_004_002', 2)],\n",
+ " [('x_005_001', 1), ('x_005_002', 2)],\n",
+ " [('x_006_001', 1), ('x_006_002', 2)]]"
+ ]
+ },
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "qubols.all_expr"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3.8.0 ('qubols')",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.0"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "390591a6667b05d6f83558ed597f55be1305d4de992db830679d199a6a0e520c"
+ }
+ },
+ "widgets": {
+ "application/vnd.jupyter.widget-state+json": {
+ "state": {
+ "17046f96803d48aa8c63b99a5c89e6f3": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "1a46e33438a648dd839fe5fd43b9582b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "1f812fe9a02b41b885f01e3190957acf": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": "\n \". . . . right \"\n ",
+ "grid_template_columns": "20% 20% 20% 20% 20%",
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "100%"
+ }
+ },
+ "20439ee3a84741dc9a137f7964898fc3": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_f0e6a746eff140269e915ef65de640c7",
+ "placeholder": "",
+ "style": "IPY_MODEL_96316857896d44328b3898d849594ae7",
+ "value": "Status
"
+ }
+ },
+ "246d39f98fdb4892bc1d5bfb88d2f1cd": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "27e0478b2a9c4533b2e67eac937cbebc": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HBoxModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_ac5a0f78ef8140a2abdf035fd1751936",
+ "IPY_MODEL_5ff6f36eaa894a339210fc29fdbeedcf",
+ "IPY_MODEL_20439ee3a84741dc9a137f7964898fc3",
+ "IPY_MODEL_eef64edafd8f47c885da65fa3ca0ab8a",
+ "IPY_MODEL_a38db3ffdfc848c0b0150e42b3509be5"
+ ],
+ "layout": "IPY_MODEL_fc018f99fbb44aa9beb54a8e6be5209e"
+ }
+ },
+ "2f981df37e914685992f4564103ef872": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "3aa67247d1a9433f87b13ce1370c8b1c": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "190px"
+ }
+ },
+ "40a8f99fef5b4aad89f533edcb091c3f": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "ButtonStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "ButtonStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "button_color": null,
+ "font_weight": ""
+ }
+ },
+ "46f75da5f7ab4f33b4df8618ccffde6b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "5ff6f36eaa894a339210fc29fdbeedcf": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_9e036ff6f31e4efb9471d371db06f533",
+ "placeholder": "",
+ "style": "IPY_MODEL_1a46e33438a648dd839fe5fd43b9582b",
+ "value": "Backend
"
+ }
+ },
+ "608e06da96f840e890006ad286afc34b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_74038cd5fbe8491ba5457f6cc81f7b5a",
+ "placeholder": "",
+ "style": "IPY_MODEL_8569084253df4279b752a85c0b99027b",
+ "value": "Circuit Properties
"
+ }
+ },
+ "74038cd5fbe8491ba5457f6cc81f7b5a": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": "0px 0px 10px 0px",
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "8569084253df4279b752a85c0b99027b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "917c693fd8d84f2e99f59d75cd5062c2": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "GridBoxModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "GridBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "GridBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_b7e87c3bbc404502ab1550d64f86c473"
+ ],
+ "layout": "IPY_MODEL_1f812fe9a02b41b885f01e3190957acf"
+ }
+ },
+ "96316857896d44328b3898d849594ae7": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "9e036ff6f31e4efb9471d371db06f533": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "145px"
+ }
+ },
+ "a38db3ffdfc848c0b0150e42b3509be5": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_2f981df37e914685992f4564103ef872",
+ "placeholder": "",
+ "style": "IPY_MODEL_246d39f98fdb4892bc1d5bfb88d2f1cd",
+ "value": "Message
"
+ }
+ },
+ "ac5a0f78ef8140a2abdf035fd1751936": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_3aa67247d1a9433f87b13ce1370c8b1c",
+ "placeholder": "",
+ "style": "IPY_MODEL_46f75da5f7ab4f33b4df8618ccffde6b",
+ "value": "Job ID
"
+ }
+ },
+ "b7e87c3bbc404502ab1550d64f86c473": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "ButtonModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "ButtonModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "ButtonView",
+ "button_style": "primary",
+ "description": "Clear",
+ "disabled": false,
+ "icon": "",
+ "layout": "IPY_MODEL_f6a39516121743099bece32bc0c3c696",
+ "style": "IPY_MODEL_40a8f99fef5b4aad89f533edcb091c3f",
+ "tooltip": ""
+ }
+ },
+ "eef64edafd8f47c885da65fa3ca0ab8a": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_ef270ca07615429ab689824b66fdb1ff",
+ "placeholder": "",
+ "style": "IPY_MODEL_17046f96803d48aa8c63b99a5c89e6f3",
+ "value": "Queue
"
+ }
+ },
+ "ef270ca07615429ab689824b66fdb1ff": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "70px"
+ }
+ },
+ "f0e6a746eff140269e915ef65de640c7": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "95px"
+ }
+ },
+ "f6a39516121743099bece32bc0c3c696": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": "right",
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": "0px 0px 0px 0px",
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "70px"
+ }
+ },
+ "fc018f99fbb44aa9beb54a8e6be5209e": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": "0px 0px 0px 37px",
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "600px"
+ }
+ }
+ },
+ "version_major": 2,
+ "version_minor": 0
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/example/qubo_poly_mixed_inverse.ipynb b/example/qubo_poly_mixed_inverse.ipynb
new file mode 100644
index 0000000..db99a7f
--- /dev/null
+++ b/example/qubo_poly_mixed_inverse.ipynb
@@ -0,0 +1,1455 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "tags": [
+ "remove_cell"
+ ]
+ },
+ "source": [
+ "# QUBO formulation of polynomial equation"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Use case\n",
+ "\n",
+ "To illustrate the metohod we are taking the equation of the two node water system that reads:\n",
+ "\n",
+ "$$\n",
+ "-1 - x_0 + x_1 = 0 \\\\\n",
+ " 1 - x_1 = 0 \\\\\n",
+ " 2 - q x_0^2 - x_2 = 0 \\\\\n",
+ " -p x_1^2 + x_2 - x_3 = 0 \n",
+ "$$\n",
+ "\n",
+ "with $q$ and $p$ paramerers taking disrete values either 1 or 2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "\n",
+ "def nlfunc(input):\n",
+ " x0,x1,x2,x3 = input\n",
+ " q, p = parameters\n",
+ "\n",
+ " def f0():\n",
+ " return -1 - x0 + x1\n",
+ " \n",
+ " def f1():\n",
+ " return 1 - x1\n",
+ " \n",
+ " def f2():\n",
+ " return 2 - q*x0**2 - x2\n",
+ "\n",
+ " def f3():\n",
+ " return -p*x1**2 + x2 - x3\n",
+ " \n",
+ " return np.array([f0(), f1(), f2(), f3()])\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Classical Solution\n",
+ "\n",
+ "The solution of such a small system can be obtained by newton raphson"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[0, 0] [-1.11022091e-16 1.00000000e+00 2.00000000e+00 2.00000000e+00]\n",
+ "[0, 1] [1.11027266e-16 1.00000000e+00 2.00000000e+00 1.00000000e+00]\n",
+ "[0, 2] [2.77554623e-17 1.00000000e+00 2.00000000e+00 1.54154467e-13]\n",
+ "[0, 3] [-1.85031227e-17 1.00000000e+00 2.00000000e+00 -1.00000000e+00]\n",
+ "[1, 0] [6.93889993e-17 1.00000000e+00 2.00000000e+00 2.00000000e+00]\n",
+ "[1, 1] [-5.55092659e-17 1.00000000e+00 2.00000000e+00 1.00000000e+00]\n",
+ "[1, 2] [7.31615402e-22 1.00000000e+00 2.00000000e+00 2.28317365e-13]\n",
+ "[1, 3] [-1.85048129e-17 1.00000000e+00 2.00000000e+00 -1.00000000e+00]\n",
+ "[2, 0] [-1.04982791e-21 1.00000000e+00 2.00000000e+00 2.00000000e+00]\n",
+ "[2, 1] [-1.11019865e-16 1.00000000e+00 2.00000000e+00 1.00000000e+00]\n",
+ "[2, 2] [-5.55111579e-17 1.00000000e+00 2.00000000e+00 2.86937141e-13]\n",
+ "[2, 3] [ 3.2381865e-17 1.0000000e+00 2.0000000e+00 -1.0000000e+00]\n",
+ "[3, 0] [1.1102262e-16 1.0000000e+00 2.0000000e+00 2.0000000e+00]\n",
+ "[3, 1] [-5.00638141e-22 1.00000000e+00 2.00000000e+00 1.00000000e+00]\n",
+ "[3, 2] [-1.26205789e-21 1.00000000e+00 2.00000000e+00 0.00000000e+00]\n",
+ "[3, 3] [ 4.51043621e-17 1.00000000e+00 2.00000000e+00 -1.00000000e+00]\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/nico/QuantumApplicationLab/QuantumNewtonRaphson/quantum_newton_raphson/utils.py:74: SparseEfficiencyWarning: spsolve requires A be CSC or CSR matrix format\n",
+ " warn(\"spsolve requires A be CSC or CSR matrix format\", SparseEfficiencyWarning)\n"
+ ]
+ }
+ ],
+ "source": [
+ "from quantum_newton_raphson.newton_raphson import newton_raphson\n",
+ "\n",
+ "parameters_list = [[i, j] for i in range(4) for j in range(4)] \n",
+ "\n",
+ "for parameters in parameters_list:\n",
+ " initial_point = np.random.rand(4)\n",
+ " res = newton_raphson(nlfunc, initial_point)\n",
+ " assert np.allclose(nlfunc(res.solution), 0)\n",
+ " print(parameters, res.solution)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## 2. QUBO formalism for linear systems\n",
+ "\n",
+ "The Quandratic Unconstrainted Binary Optimization problem, or QUBO, allows to minimize the cost function :\n",
+ "\n",
+ "$$\n",
+ "E(x) = x^{T}Qx\n",
+ "$$\n",
+ "\n",
+ "where the variables $x_i$ are binaries, i.e. the are 0 or 1. The equation above can be rewritten as :\n",
+ "\n",
+ "$$\n",
+ "E(x) = \\sum_i Q_{ii}x_i + \\sum_{ij} Q_{ij}x_ix_j\n",
+ "$$\n",
+ "\n",
+ "that is very similar to the Ising model, basis of the quantum annealler architecture. \n",
+ "\n",
+ "### Encoding real numbers in binary variables\n",
+ "\n",
+ "In the QUBO problems, variables are binaries and we of course want to solve for real numbers in our case. There ar e different ways to encode real numbers in multiple binaries. In our case since the variables are between -1.0 and 1.0 we can use the following encoding : \n",
+ "\n",
+ "$$\n",
+ "r_i = a \\sum_n x_n 2^{n} - x_{k+n} 2^{n} \n",
+ "$$\n",
+ "\n",
+ "where $a$ is a normalization constant. THis encoding is created in the `SolutionVector` class that allows to encode/decode real numbers in a series of binaries variables. We use here the `RealUnitQbitEncoding` to obtain real numbers between -1 and 1. The number of qbit controls the precision of the reals we can obtain."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Polynomial equation\n",
+ "\n",
+ "We first write the polynomial equation as follow (https://www.nature.com/articles/s41598-019-46729-0) \n",
+ "\n",
+ "$$\n",
+ "F(X) = 0\n",
+ "$$\n",
+ "\n",
+ "with\n",
+ "\n",
+ "$$\n",
+ "F_i = P_i^{(0)} + \\sum_j P_{ij}^{(1)}x_j + \\sum_{jk} P_{ijk}^{(2)}x_j x_k = 0\n",
+ "$$\n",
+ "\n",
+ "To solve the system we minimize the residual sum of square\n",
+ "\n",
+ "$$\n",
+ "\\chi^2 = [P^{(0)} + P^{(1)} X + P^{(2)} X X.T ]^2\n",
+ "$$\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Use case\n",
+ "\n",
+ "To illustrate the metohod we are taking the equation of the two node water system that reads:\n",
+ "\n",
+ "$$\n",
+ "-1 - x_0 + x_1 = 0 \\\\\n",
+ " 1 - x_1 = 0 \\\\\n",
+ " 2 - q x_0^2 - x_2 = 0 \\\\\n",
+ " -p x_1^2 + x_2 - x_3 = 0 \\\\\n",
+ " c( M - q - p) \\rightarrow 0 \n",
+ "$$\n",
+ "\n",
+ "with $q$ and $p$ paramerers taking disrete values either 1 or 2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import sparse\n",
+ "def define_matrices():\n",
+ " \n",
+ " # system of equations\n",
+ " num_equations = 5\n",
+ " num_variables = 6\n",
+ " c = 1E-1\n",
+ " M = 6\n",
+ "\n",
+ " P0 = np.zeros((num_equations,1))\n",
+ " P0[0] = -1\n",
+ " P0[1] = 1\n",
+ " P0[2] = 2\n",
+ " P0[3] = 0\n",
+ " P0[4] = c*M\n",
+ "\n",
+ " P1 = np.zeros((num_equations, num_variables))\n",
+ " P1[0, 0] = -1\n",
+ " P1[0, 1] = 1\n",
+ "\n",
+ " P1[1, 1] = -1\n",
+ "\n",
+ " P1[2, 2] = -1\n",
+ "\n",
+ " P1[3, 2] = 1 \n",
+ " P1[3, 3] = -1\n",
+ "\n",
+ " # cost\n",
+ " P1[4,4] = -c\n",
+ " P1[4,5] = -c\n",
+ " \n",
+ "\n",
+ " P2 = np.zeros((num_equations, num_variables, num_variables))\n",
+ "\n",
+ "\n",
+ " P3 = np.zeros((num_equations, num_variables, num_variables, num_variables))\n",
+ " P3[2, 0, 0, 4] = -1\n",
+ " P3[3, 1, 1, 5] = -1\n",
+ "\n",
+ "\n",
+ " return sparse.COO(P0), sparse.COO(P1), sparse.COO(P2), sparse.COO(P3)\n",
+ "\n",
+ "matrices = define_matrices()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## 3. Solving the system\n",
+ "\n",
+ "We will use here the `SimulatedAnnealingSampler` to be able to run that code locally. Quantum solvers are available through the Leap cloud service."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from qubols.qubo_poly import QUBO_POLY\n",
+ "from qubols.encodings import PositiveQbitEncoding\n",
+ "import dimod\n",
+ "# options = {'num_reads':20, 'num_qbits':2, 'sampler':dimod.ExactSolver(), \n",
+ "# 'encoding': PositiveQbitEncoding}\n",
+ "# qubols=QUBO_POLY(options)\n",
+ "# sol = qubols.solve(matrices)\n",
+ "# sol"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Switch sampler"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([0., 1., 2., 0., 3., 2.])"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import neal\n",
+ "sampler = neal.SimulatedAnnealingSampler()\n",
+ "options = {'num_reads':100, 'num_qbits':2, 'sampler':sampler, \n",
+ " 'encoding': PositiveQbitEncoding}\n",
+ "qubols=QUBO_POLY(options)\n",
+ "\n",
+ "sol = qubols.solve(matrices)\n",
+ "sol"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Add slack variables"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "bqm = qubols.create_qubo_matrix(qubols.x)\n",
+ "# slacks1 = bqm.add_linear_inequality_constraint([(\"x_003_001\",1), (\"x_003_002\",2)], lagrange_multiplier=2/3, label=\"head1\", lb=0, ub=1)\n",
+ "slacks2 = bqm.add_linear_inequality_constraint(qubols.all_expr[3], lagrange_multiplier=1, label=\"head2\", lb=1, ub=2)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import neal\n",
+ "sampler = neal.SimulatedAnnealingSampler()\n",
+ "sampleset = sampler.sample(bqm, num_reads = 100)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([0., 1., 2., 1., 3., 1.])"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sol = sampleset.lowest()\n",
+ "idx, vars, data = qubols.extract_data(sol)\n",
+ "sol = qubols.solution_vector.decode_solution(data)\n",
+ "sol"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([0., 0., 0., 0.])"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "parameters = sol[4:]\n",
+ "nlfunc(sol[:4])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle \\left[\\begin{matrix}x_{001 001} + 2 x_{001 002}\\\\x_{002 001} + 2 x_{002 002}\\\\x_{003 001} + 2 x_{003 002}\\\\x_{004 001} + 2 x_{004 002}\\\\x_{005 001} + 2 x_{005 002}\\\\x_{006 001} + 2 x_{006 002}\\end{matrix}\\right]$"
+ ],
+ "text/plain": [
+ "Matrix([\n",
+ "[x_001_001 + 2*x_001_002],\n",
+ "[x_002_001 + 2*x_002_002],\n",
+ "[x_003_001 + 2*x_003_002],\n",
+ "[x_004_001 + 2*x_004_002],\n",
+ "[x_005_001 + 2*x_005_002],\n",
+ "[x_006_001 + 2*x_006_002]])"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "qubols.x"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "qubols.solution_vector"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from qubols.solution_vector import SolutionVector\n",
+ "from qubols.encodings import PositiveQbitEncoding, RangedEfficientEncoding \n",
+ "\n",
+ "sol_vec0 = SolutionVector(2,2,PositiveQbitEncoding)\n",
+ "sol_vec1 = SolutionVector(3,3, PositiveQbitEncoding)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "x0 = sol_vec0.create_polynom_vector()\n",
+ "x1 = sol_vec1.create_polynom_vector()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 34,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle x_{001 001} + 2 x_{001 002}$"
+ ],
+ "text/plain": [
+ "x_001_001 + 2*x_001_002"
+ ]
+ },
+ "execution_count": 34,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "x0[0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle \\left[\\begin{matrix}x_{001 001} + 2 x_{001 002} + 4 x_{001 003}\\\\x_{002 001} + 2 x_{002 002} + 4 x_{002 003}\\\\x_{003 001} + 2 x_{003 002} + 4 x_{003 003}\\end{matrix}\\right]$"
+ ],
+ "text/plain": [
+ "Matrix([\n",
+ "[x_001_001 + 2*x_001_002 + 4*x_001_003],\n",
+ "[x_002_001 + 2*x_002_002 + 4*x_002_003],\n",
+ "[x_003_001 + 2*x_003_002 + 4*x_003_003]])"
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "x1"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(2, 1)"
+ ]
+ },
+ "execution_count": 22,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "x0.shape"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[x_001_001, x_001_002, x_001_003]"
+ ]
+ },
+ "execution_count": 31,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sol_vec1.encoded_reals[0].variables"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle \\left[\\begin{matrix}x_{001 001} + 2 x_{001 002}\\\\x_{002 001} + 2 x_{002 002}\\end{matrix}\\right]$"
+ ],
+ "text/plain": [
+ "Matrix([\n",
+ "[x_001_001 + 2*x_001_002],\n",
+ "[x_002_001 + 2*x_002_002]])"
+ ]
+ },
+ "execution_count": 32,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "x0"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 33,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle \\left[\\begin{matrix}x_{001 001} + 2 x_{001 002} + 4 x_{001 003}\\\\x_{002 001} + 2 x_{002 002} + 4 x_{002 003}\\\\x_{003 001} + 2 x_{003 002} + 4 x_{003 003}\\end{matrix}\\right]$"
+ ],
+ "text/plain": [
+ "Matrix([\n",
+ "[x_001_001 + 2*x_001_002 + 4*x_001_003],\n",
+ "[x_002_001 + 2*x_002_002 + 4*x_002_003],\n",
+ "[x_003_001 + 2*x_003_002 + 4*x_003_003]])"
+ ]
+ },
+ "execution_count": 33,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "x1"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class MixedSolutionVector(object):\n",
+ "\n",
+ " def __init__(self, solution_vectors):\n",
+ " self.solution_vectors = solution_vectors\n",
+ "\n",
+ " def create_encoding(self):\n",
+ " \"\"\"Create the eocnding for all the unknowns\n",
+ "\n",
+ "\n",
+ " Returns:\n",
+ " list[RealEncoded]:\n",
+ " \"\"\"\n",
+ " encoded_reals = []\n",
+ "\n",
+ " idx_vars = 0\n",
+ " for sol_vec in self.solution_vectors:\n",
+ " is_ranged_encoding = sol_vec.encoding == RangedEfficientEncoding\n",
+ " for i in range(sol_vec.size):\n",
+ " var_base_name = sol_vec.base_name + \"_%03d\" % (idx_vars + 1)\n",
+ " idx_vars += 1\n",
+ "\n",
+ " if is_ranged_encoding:\n",
+ " args = (sol_vec.nqbit, sol_vec.range[i], sol_vec.offset[i], var_base_name)\n",
+ " else:\n",
+ " args = (sol_vec.nqbit, var_base_name)\n",
+ " encoded_reals.append(sol_vec.encoding(*args))\n",
+ " return encoded_reals\n",
+ "\n",
+ "msv = MixedSolutionVector([sol_vec0, sol_vec1])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "AttributeError",
+ "evalue": "'MixedSolutionVector' object has no attribute 'base_name'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[41], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mmsv\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate_encoding\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
+ "Cell \u001b[0;32mIn[40], line 19\u001b[0m, in \u001b[0;36mMixedSolutionVector.create_encoding\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 17\u001b[0m is_ranged_encoding \u001b[38;5;241m=\u001b[39m sol_vec\u001b[38;5;241m.\u001b[39mencoding \u001b[38;5;241m==\u001b[39m RangedEfficientEncoding\n\u001b[1;32m 18\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(sol_vec\u001b[38;5;241m.\u001b[39msize):\n\u001b[0;32m---> 19\u001b[0m var_base_name \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbase_name\u001b[49m \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m_\u001b[39m\u001b[38;5;132;01m%03d\u001b[39;00m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;241m%\u001b[39m (idx_vars \u001b[38;5;241m+\u001b[39m \u001b[38;5;241m1\u001b[39m)\n\u001b[1;32m 20\u001b[0m idx_vars \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[1;32m 22\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m is_ranged_encoding:\n",
+ "\u001b[0;31mAttributeError\u001b[0m: 'MixedSolutionVector' object has no attribute 'base_name'"
+ ]
+ }
+ ],
+ "source": [
+ "msv.create_encoding()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3.8.0 ('qubols')",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.0"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "390591a6667b05d6f83558ed597f55be1305d4de992db830679d199a6a0e520c"
+ }
+ },
+ "widgets": {
+ "application/vnd.jupyter.widget-state+json": {
+ "state": {
+ "17046f96803d48aa8c63b99a5c89e6f3": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "1a46e33438a648dd839fe5fd43b9582b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "1f812fe9a02b41b885f01e3190957acf": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": "\n \". . . . right \"\n ",
+ "grid_template_columns": "20% 20% 20% 20% 20%",
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "100%"
+ }
+ },
+ "20439ee3a84741dc9a137f7964898fc3": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_f0e6a746eff140269e915ef65de640c7",
+ "placeholder": "",
+ "style": "IPY_MODEL_96316857896d44328b3898d849594ae7",
+ "value": "Status
"
+ }
+ },
+ "246d39f98fdb4892bc1d5bfb88d2f1cd": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "27e0478b2a9c4533b2e67eac937cbebc": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HBoxModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_ac5a0f78ef8140a2abdf035fd1751936",
+ "IPY_MODEL_5ff6f36eaa894a339210fc29fdbeedcf",
+ "IPY_MODEL_20439ee3a84741dc9a137f7964898fc3",
+ "IPY_MODEL_eef64edafd8f47c885da65fa3ca0ab8a",
+ "IPY_MODEL_a38db3ffdfc848c0b0150e42b3509be5"
+ ],
+ "layout": "IPY_MODEL_fc018f99fbb44aa9beb54a8e6be5209e"
+ }
+ },
+ "2f981df37e914685992f4564103ef872": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "3aa67247d1a9433f87b13ce1370c8b1c": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "190px"
+ }
+ },
+ "40a8f99fef5b4aad89f533edcb091c3f": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "ButtonStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "ButtonStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "button_color": null,
+ "font_weight": ""
+ }
+ },
+ "46f75da5f7ab4f33b4df8618ccffde6b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "5ff6f36eaa894a339210fc29fdbeedcf": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_9e036ff6f31e4efb9471d371db06f533",
+ "placeholder": "",
+ "style": "IPY_MODEL_1a46e33438a648dd839fe5fd43b9582b",
+ "value": "Backend
"
+ }
+ },
+ "608e06da96f840e890006ad286afc34b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_74038cd5fbe8491ba5457f6cc81f7b5a",
+ "placeholder": "",
+ "style": "IPY_MODEL_8569084253df4279b752a85c0b99027b",
+ "value": "Circuit Properties
"
+ }
+ },
+ "74038cd5fbe8491ba5457f6cc81f7b5a": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": "0px 0px 10px 0px",
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": null
+ }
+ },
+ "8569084253df4279b752a85c0b99027b": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "917c693fd8d84f2e99f59d75cd5062c2": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "GridBoxModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "GridBoxModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "GridBoxView",
+ "box_style": "",
+ "children": [
+ "IPY_MODEL_b7e87c3bbc404502ab1550d64f86c473"
+ ],
+ "layout": "IPY_MODEL_1f812fe9a02b41b885f01e3190957acf"
+ }
+ },
+ "96316857896d44328b3898d849594ae7": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "DescriptionStyleModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "DescriptionStyleModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "StyleView",
+ "description_width": ""
+ }
+ },
+ "9e036ff6f31e4efb9471d371db06f533": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "145px"
+ }
+ },
+ "a38db3ffdfc848c0b0150e42b3509be5": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_2f981df37e914685992f4564103ef872",
+ "placeholder": "",
+ "style": "IPY_MODEL_246d39f98fdb4892bc1d5bfb88d2f1cd",
+ "value": "Message
"
+ }
+ },
+ "ac5a0f78ef8140a2abdf035fd1751936": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_3aa67247d1a9433f87b13ce1370c8b1c",
+ "placeholder": "",
+ "style": "IPY_MODEL_46f75da5f7ab4f33b4df8618ccffde6b",
+ "value": "Job ID
"
+ }
+ },
+ "b7e87c3bbc404502ab1550d64f86c473": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "ButtonModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "ButtonModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "ButtonView",
+ "button_style": "primary",
+ "description": "Clear",
+ "disabled": false,
+ "icon": "",
+ "layout": "IPY_MODEL_f6a39516121743099bece32bc0c3c696",
+ "style": "IPY_MODEL_40a8f99fef5b4aad89f533edcb091c3f",
+ "tooltip": ""
+ }
+ },
+ "eef64edafd8f47c885da65fa3ca0ab8a": {
+ "model_module": "@jupyter-widgets/controls",
+ "model_module_version": "1.5.0",
+ "model_name": "HTMLModel",
+ "state": {
+ "_dom_classes": [],
+ "_model_module": "@jupyter-widgets/controls",
+ "_model_module_version": "1.5.0",
+ "_model_name": "HTMLModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/controls",
+ "_view_module_version": "1.5.0",
+ "_view_name": "HTMLView",
+ "description": "",
+ "description_tooltip": null,
+ "layout": "IPY_MODEL_ef270ca07615429ab689824b66fdb1ff",
+ "placeholder": "",
+ "style": "IPY_MODEL_17046f96803d48aa8c63b99a5c89e6f3",
+ "value": "Queue
"
+ }
+ },
+ "ef270ca07615429ab689824b66fdb1ff": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "70px"
+ }
+ },
+ "f0e6a746eff140269e915ef65de640c7": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "95px"
+ }
+ },
+ "f6a39516121743099bece32bc0c3c696": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": "right",
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": null,
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": "0px 0px 0px 0px",
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "70px"
+ }
+ },
+ "fc018f99fbb44aa9beb54a8e6be5209e": {
+ "model_module": "@jupyter-widgets/base",
+ "model_module_version": "1.2.0",
+ "model_name": "LayoutModel",
+ "state": {
+ "_model_module": "@jupyter-widgets/base",
+ "_model_module_version": "1.2.0",
+ "_model_name": "LayoutModel",
+ "_view_count": null,
+ "_view_module": "@jupyter-widgets/base",
+ "_view_module_version": "1.2.0",
+ "_view_name": "LayoutView",
+ "align_content": null,
+ "align_items": null,
+ "align_self": null,
+ "border": null,
+ "bottom": null,
+ "display": null,
+ "flex": null,
+ "flex_flow": null,
+ "grid_area": null,
+ "grid_auto_columns": null,
+ "grid_auto_flow": null,
+ "grid_auto_rows": null,
+ "grid_column": null,
+ "grid_gap": null,
+ "grid_row": null,
+ "grid_template_areas": null,
+ "grid_template_columns": null,
+ "grid_template_rows": null,
+ "height": null,
+ "justify_content": null,
+ "justify_items": null,
+ "left": null,
+ "margin": "0px 0px 0px 37px",
+ "max_height": null,
+ "max_width": null,
+ "min_height": null,
+ "min_width": null,
+ "object_fit": null,
+ "object_position": null,
+ "order": null,
+ "overflow": null,
+ "overflow_x": null,
+ "overflow_y": null,
+ "padding": null,
+ "right": null,
+ "top": null,
+ "visibility": null,
+ "width": "600px"
+ }
+ }
+ },
+ "version_major": 2,
+ "version_minor": 0
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/qubols/encodings.py b/qubols/encodings.py
index b3d2e83..c56928d 100644
--- a/qubols/encodings.py
+++ b/qubols/encodings.py
@@ -1,4 +1,6 @@
from sympy import Symbol
+import itertools
+import numpy as np
class BaseQbitEncoding(object):
@@ -15,6 +17,14 @@ def __init__(self, nqbit, var_base_name):
self.var_base_name = var_base_name
self.variables = self.create_variable()
+ def set_var_base_name(self, var_base_name):
+ """set the variable base name
+
+ Args:
+ var_base_name (_type_): _description_
+ """
+ self.var_base_name = var_base_name
+
def create_variable(self):
"""Create all the variabes/qbits required for the expansion
@@ -26,6 +36,57 @@ def create_variable(self):
variables.append(Symbol(self.var_base_name + "_%03d" % (i + 1)))
return variables
+ def create_polynom(self):
+ raise NotImplementedError("Implement create_polynom")
+
+ def decode_polynom(self, data):
+ raise NotImplementedError("Implement decode_polynom")
+
+ def get_max_value(self):
+ """Get the maximum value of the encoding
+
+ Returns:
+ float: max value
+ """
+ return self.decode_polynom([1] * self.nqbit)
+
+ def get_possible_values(self):
+ """get all the posible values encoded
+
+ Returns:
+ _type_: _description_
+ """
+
+ values = []
+ for data in itertools.product([0, 1], repeat=self.nqbit):
+ values.append(self.decode_polynom(list(data)[::-1]))
+ return values
+
+ def find_closest(self, float):
+ """finds the closest possible encoded number to float
+
+ Args:
+ float (_type_): _description_
+ """
+
+ min_diff = 1e12
+ closest_value = None
+ binary_encoding = None
+ for data in itertools.product([0, 1], repeat=self.nqbit):
+ val = self.decode_polynom(list(data)[::-1])
+ if np.abs(val - float) < min_diff:
+ min_diff = np.abs(val - float)
+ closest_value = val
+ binary_encoding = list(data)[::-1]
+
+ return closest_value, binary_encoding
+
+ def get_average_precision(self):
+ """get the mean precision on the encoded variables"""
+ vals = self.get_possible_values()
+ z = vals - np.roll(vals, 1)
+ return np.mean(z[1:])
+
class RangedEfficientEncoding(BaseQbitEncoding):
@@ -47,7 +108,10 @@ def create_polynom(self):
Returns:
sympy expression
"""
- out = -(2 ** (self.nqbit - 1)) * self.variables[0] * self.max_absval[0]
+ out = (
+ self.offset
+ - (2 ** (self.nqbit - 1)) * self.variables[0] * self.max_absval[0]
+ )
for i in range(self.nqbit - 1):
out += 2 ** (i) * self.variables[i + 1] * self.max_absval[i]
return out
@@ -59,7 +123,7 @@ def decode_polynom(self, data):
Returns:
sympy expression
"""
- out = -(2 ** (self.nqbit - 1)) * data[0] * self.max_absval[0]
+ out = self.offset - (2 ** (self.nqbit - 1)) * data[0] * self.max_absval[0]
for i in range(self.nqbit - 1):
out += 2 ** (i) * data[i + 1] * self.max_absval[i]
return out
@@ -185,8 +249,10 @@ def decode_polynom(self, data):
class PositiveQbitEncoding(BaseQbitEncoding):
- def __init__(self, nqbit, var_base_name):
+ def __init__(self, nqbit, var_base_name, offset=0, step=1):
super().__init__(nqbit, var_base_name)
+ self.offset = offset
+ self.step = step
def create_polynom(self):
"""
@@ -195,14 +261,55 @@ def create_polynom(self):
Returns:
sympy expression
"""
- out = 0.0
+ out = self.offset
for i in range(self.nqbit):
- out += 2**i * self.variables[i]
+ out += self.step * 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]
+ out = self.offset
+ for i in range(self.nqbit):
+ out += self.step * 2**i * data[i]
+ return out
+
+
+class DiscreteValuesEncoding(BaseQbitEncoding):
+
+ def __init__(self, values, nqbit, var_base_name):
+ super().__init__(nqbit, var_base_name)
+ self.discrete_values = values
+ self.coefs = self.get_coefficients()
+ self.offset = 0
+
+ def get_coefficients(self):
+ """get the lstqst coefficients"""
+ nvalues = len(self.discrete_values)
+ nqbit = self.nqbit
+ A = np.zeros((nvalues, nqbit + 1))
+ c = [1] + [2**i for i in range(nqbit)]
+ for idx in range(nvalues):
+ row = [1] + [float(i) for i in np.binary_repr(idx, width=nqbit)][::-1]
+ A[idx, :] = row
+ A = A * c
+
+ coefs, res, rank, s = np.linalg.lstsq(A, self.discrete_values)
+
+ return coefs
+
+ def create_polynom(self):
+ """
+ Create the polynoms of the expansion
+
+ Returns:
+ sympy expression
+ """
+ out = self.coefs[0]
+ for i in range(self.nqbit):
+ out += self.coefs[i + 1] * 2**i * self.variables[i]
+ return out
+
+ def decode_polynom(self, data):
+ out = self.coefs[0]
+ for i in range(self.nqbit):
+ out += self.coefs[i + 1] * 2**i * data[i]
return out
diff --git a/qubols/mixed_solution_vector.py b/qubols/mixed_solution_vector.py
new file mode 100644
index 0000000..279ba27
--- /dev/null
+++ b/qubols/mixed_solution_vector.py
@@ -0,0 +1,126 @@
+from sympy.matrices import Matrix
+import numpy as np
+from copy import deepcopy
+from .encodings import RangedEfficientEncoding
+
+
+class MixedSolutionVector(object):
+
+ def __init__(self, solution_vectors):
+ """init the mixed solution vector
+
+ Args:
+ solution_vectors (List): A list of SolutionVector instances
+ """
+ self.solution_vectors = solution_vectors
+ self.nqbit = []
+ self.idx_start_data = self.get_indexes_data()
+ self.encoded_reals = self.create_encoding()
+
+ def create_encoding(self):
+ """Create the enconding for all the unknowns
+
+
+ Returns:
+ list[RealEncoded]:
+ """
+ encoded_reals = []
+
+ idx_vars = 0
+ for sol_vec in self.solution_vectors:
+ is_ranged_encoding = sol_vec.encoding == RangedEfficientEncoding
+ for i in range(sol_vec.size):
+ var_base_name = sol_vec.base_name + "_%03d" % (idx_vars + 1)
+ idx_vars += 1
+
+ if is_ranged_encoding:
+ args = (
+ sol_vec.nqbit,
+ sol_vec.range[i],
+ sol_vec.offset[i],
+ var_base_name,
+ )
+ else:
+ args = (sol_vec.nqbit, var_base_name)
+ encoded_reals.append(sol_vec.encoding(*args))
+ self.nqbit.append(sol_vec.nqbit)
+ return encoded_reals
+
+ def get_indexes_data(self):
+ """Get the indices of the start/end of the data for each encoding
+
+ Returns:
+ np.array: lis of start/end index
+ """
+ idx_start_data = [0]
+ for sv in self.solution_vectors:
+ idx_start_data.append(sv.nqbit * sv.size)
+ idx_start_data[-1] += 1
+ return np.cumsum(idx_start_data)
+
+ 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):
+ """Decode the solution
+
+ Args:
+ data (list): data from the annealer
+
+ Returns:
+ list: decoded numbers
+ """
+ sol = []
+ for iv, sv in enumerate(self.solution_vectors):
+ idx_start = self.idx_start_data[iv]
+ idx_end = self.idx_start_data[iv + 1]
+ sv_data = data[idx_start:idx_end]
+ sol.append(list(sv.decode_solution(sv_data)))
+ idx_start += sv.size
+ return sol
+
+
+class MixedSolutionVector_V2(MixedSolutionVector):
+
+ def __init__(self, solution_vectors):
+ """init the mixed solution vector
+
+ Args:
+ solution_vectors (List): A list of SolutionVector instances
+ """
+ self.solution_vectors = solution_vectors
+ self.nqbit = []
+ self.idx_start_data = self.get_indexes_data()
+ self.encoded_reals = self.create_encoding()
+
+ def create_encoding(self):
+ """Create the enconding for all the unknowns
+
+
+ Returns:
+ list[RealEncoded]:
+ """
+ encoded_reals = []
+
+ idx_vars = 0
+ for sol_vec in self.solution_vectors:
+
+ for i in range(sol_vec.size):
+ var_base_name = sol_vec.base_name + "_%03d" % (idx_vars + 1)
+ idx_vars += 1
+
+ x = deepcopy(sol_vec.encoding)
+ x.set_var_base_name(var_base_name)
+ x.variables = x.create_variable()
+ encoded_reals.append(x)
+ self.nqbit.append(sol_vec.nqbit)
+
+ return encoded_reals
diff --git a/qubols/qubo_poly.py b/qubols/qubo_poly.py
new file mode 100644
index 0000000..8028338
--- /dev/null
+++ b/qubols/qubo_poly.py
@@ -0,0 +1,304 @@
+from sympy.matrices import Matrix
+import numpy as np
+from typing import Optional, Union, Dict
+import neal
+import dimod
+from .solution_vector import SolutionVector_V2 as SolutionVector
+
+
+class QUBO_POLY:
+
+ def __init__(
+ self,
+ solution_vector: SolutionVector,
+ options: Optional[Union[Dict, None]] = None,
+ ):
+ """Polynomial of degree 2 Solver using QUBO
+
+ Solve the following equation
+
+ ..math:
+ P_0 + P_1 x + P_2 x \otimes x = 0
+
+ Args:
+ options: dictionary of options for solving the linear system
+ """
+
+ default_solve_options = {
+ "sampler": neal.SimulatedAnnealingSampler(),
+ "num_reads": 100,
+ "verbose": False,
+ }
+ self.options = self._validate_solve_options(options, default_solve_options)
+ self.sampler = self.options.pop("sampler")
+ self.solution_vector = solution_vector
+ self.index_variables = None
+ self.mapped_variables = None
+
+ @staticmethod
+ def _validate_solve_options(
+ options: Union[Dict, None], default_solve_options: Dict
+ ) -> Dict:
+ """validate the options used for the solve methods
+
+ Args:
+ options (Union[Dict, None]): options
+ """
+ valid_keys = default_solve_options.keys()
+
+ if options is None:
+ options = 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] = default_solve_options[k]
+
+ return options
+
+ def create_bqm(self, matrices, strength=10):
+ """Create the bqm from the matrices
+
+ Args:
+ matrices (tuple): matrix of the system
+
+ Returns:
+ dimod.bqm: binary quadratic model
+ """
+
+ self.matrices = matrices
+ self.num_variables = self.matrices[1].shape[1]
+
+ self.x = self.solution_vector.create_polynom_vector()
+ self.extract_all_variables()
+
+ return self.create_qubo_matrix(self.x, strength=strength)
+
+ def sample_bqm(self, bqm, num_reads):
+ """Sample the bqm"""
+
+ sampleset = self.sampler.sample(bqm, num_reads=num_reads)
+ self.create_variables_mapping(sampleset)
+ return sampleset
+
+ def solve(self, matrices, strength=10):
+ """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.qubo_dict = self.create_bqm(matrices, strength=strength)
+
+ self.sampleset = self.sample_bqm(
+ self.qubo_dict, num_reads=self.options["num_reads"]
+ )
+ self.lowest_sol = self.sampleset.lowest()
+
+ return self.solution_vector.decode_solution(self.lowest_sol.record[0][0])
+
+ def extract_all_variables(self):
+ """Extracs all the variable names and expressions"""
+ self.all_vars = []
+ self.all_expr = []
+ for var in self.x:
+ expr = [(str(k), v) for k, v in var.as_coefficients_dict().items()]
+ self.all_expr.append(expr)
+ self.all_vars += [str(k) for k in var.as_coefficients_dict().keys()]
+
+ def create_polynom(self, x: np.ndarray):
+ """Creates the polynom from the matrices
+
+ Args:
+ x (_type_): _description_
+ """
+ self.num_equations = self.matrices[1].shape[0]
+ polynom = Matrix([0] * self.num_equations)
+
+ for imat, matrix in enumerate(self.matrices):
+
+ for idx, val in zip(matrix.coords.T, matrix.data):
+ if imat == 0:
+ polynom[idx[0]] += val
+ else:
+ polynom[idx[0]] += val * x[idx[1:]].prod()
+ return polynom
+
+ def create_qubo_matrix(self, x, strength=100, prec=None):
+ """Create the QUBO dictionary requried by dwave solvers
+ to solve the polynomial equation P0 + P1 x + P2 x x = 0
+
+
+ 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_
+ """
+
+ polynom = self.create_polynom(np.array(x))
+ polynom = polynom.T @ polynom
+ polynom = polynom[0]
+ polynom = polynom.expand()
+ polynom = polynom.as_ordered_terms()
+ polynom = self.create_poly_dict(polynom, prec=prec)
+ bqm = dimod.make_quadratic(polynom, strength=strength, vartype=dimod.BINARY)
+
+ return bqm
+
+ @staticmethod
+ def create_poly_dict(polynom, prec=None):
+ """Creates a dict from the sympy polynom
+
+ Args:
+ polynom (_type_): _description_
+
+ Returns:
+ Dict: _description_
+ """
+ out = dict()
+
+ for term in polynom:
+ m = term.args
+ if len(m) == 0:
+ continue
+
+ if len(m) == 2:
+ varname = str(m[1])
+ tmp = varname.split("**")
+ if len(tmp) == 1:
+ exponent = 1
+ else:
+ varname, exponent = tmp
+ exponent = int(exponent)
+ key = (varname,) * exponent
+
+ elif len(m) > 2:
+ key = tuple()
+ for mi in m[1:]:
+ mi = str(mi)
+ tmp = mi.split("**")
+ if len(tmp) == 1:
+ key += (tmp[0],)
+ if len(tmp) == 2:
+ varname = tmp[0]
+ exp = int(tmp[1])
+ key += (varname,) * exp
+
+ 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
+
+ def decode_solution(self, data):
+ """_summary_
+
+ Returns:
+ _type_: _description_
+ """
+ return self.solution_vector.decode_solution(data[self.index_variables])
+
+ def create_variables_mapping(self, sol):
+ """generates the index of variables in the solution vector
+
+ Args:
+ sol (_type_): _description_
+ """
+ # extract the data of the original variables
+ self.index_variables, self.mapped_variables = [], []
+ for ix, s in enumerate(sol.variables):
+ if s in self.all_vars:
+ self.index_variables.append(ix)
+ self.mapped_variables.append(s)
+
+ def compute_energy(self, vector, bqm):
+ """Compue the QUBO energy of the vecto containing the solution of the initial problem
+
+ Args:
+ vector (_type_): _description_
+ """
+ closest_vec = []
+ bin_encoding_vector = []
+ encoded_variables = []
+ for val, svec in zip(vector, self.solution_vector.encoded_reals):
+ closest_val, bin_encoding = svec.find_closest(val)
+ closest_vec.append(closest_val)
+ bin_encoding_vector += bin_encoding
+ encoded_variables += [str(sv) for sv in svec.variables]
+
+ bqm_input_variables = {}
+ for v in bqm.variables:
+ if v in encoded_variables:
+ idx = encoded_variables.index(v)
+ bqm_input_variables[v] = bin_encoding_vector[idx]
+ else:
+ var_tmp = v.split("*")
+ itmp = 0
+ for vtmp in var_tmp:
+ idx = encoded_variables.index(vtmp)
+ val = bin_encoding_vector[idx]
+ if itmp == 0:
+ bqm_input_variables[v] = val
+ itmp = 1
+ else:
+ bqm_input_variables[v] *= val
+
+ return (
+ closest_vec,
+ bin_encoding_vector,
+ encoded_variables,
+ bqm_input_variables,
+ ), bqm.energy(bqm_input_variables)
+
+ def verify_quadratic_constraints(self, sampleset):
+ """check if quadratic constraints are respected or not
+
+ Args:
+ sampleset (_type_): _description_
+ """
+ var = sampleset.lowest().variables
+ data = np.array(sampleset.lowest().record[0][0])
+
+ for v, d in zip(var, data):
+ if v not in self.mapped_variables:
+ var_tmp = v.split("*")
+ itmp = 0
+ for vtmp in var_tmp:
+ idx = self.index_variables[self.mapped_variables.index(vtmp)]
+ if itmp == 0:
+ dcomposite = data[idx]
+ itmp = 1
+ else:
+ dcomposite *= data[idx]
+ if d != dcomposite:
+ print("Error in the quadratic contratints")
+ print("%s = %d" % (v, d))
+ for vtmp in var_tmp:
+ idx = self.index_variables[self.mapped_variables.index(vtmp)]
+ print("%s = %d" % (vtmp, data[idx]))
diff --git a/qubols/qubo_poly_mixed_variables.py b/qubols/qubo_poly_mixed_variables.py
new file mode 100644
index 0000000..b13bddb
--- /dev/null
+++ b/qubols/qubo_poly_mixed_variables.py
@@ -0,0 +1,263 @@
+from sympy.matrices import Matrix
+from sympy.polys import Poly
+from copy import deepcopy
+import numpy as np
+from typing import Optional, Union, Dict, Tuple, List
+from dwave.samplers import SimulatedAnnealingSampler
+import dimod
+from .qubo_poly import QUBO_POLY
+from .mixed_solution_vector import MixedSolutionVector_V2 as MixedSolutionVector
+
+
+class QUBO_POLY_MIXED(QUBO_POLY):
+
+ def __init__(
+ self,
+ mixed_solution_vectors: MixedSolutionVector,
+ options: Optional[Union[Dict, None]] = None,
+ ):
+ """Solve the following equation
+
+ ..math:
+ P_0 + P_1 x + P_2 x^2 + ... + P_n x^n = 0
+
+ Args:
+ mixed_solution_vectors (MixedSolutionVector): Solution vector for the varialbes
+ options (Optional[Union[Dict, None]], optional): dictionary of options for solving the system. Defaults to None.
+ """
+ default_solve_options = {
+ "sampler": SimulatedAnnealingSampler(),
+ "num_reads": 100,
+ "verbose": False,
+ }
+
+ self.options = self._validate_solve_options(
+ deepcopy(options), default_solve_options
+ )
+ self.sampler = self.options.pop("sampler")
+ self.mixed_solution_vectors = mixed_solution_vectors
+
+ def create_bqm(self, matrices: Tuple, strength: float = 10) -> dimod.BQM:
+ """Create the bqm from the matrices
+
+ Args:
+ matrices (tuple): matrix of the system
+ stregth (float): couplign stregth for the substitution. Default 10
+
+ Returns:
+ dimod.bqm: binary quadratic model
+ """
+
+ self.matrices = matrices
+ self.num_variables = self.matrices[1].shape[1]
+
+ self.x = self.mixed_solution_vectors.create_polynom_vector()
+ self.extract_all_variables()
+
+ return self.create_qubo_matrix(self.x, strength=strength)
+
+ def sample_bqm(self, bqm: dimod.bqm, num_reads: int) -> dimod.SampleSet:
+ """Sample the bqm"""
+ sampleset = self.sampler.sample(bqm, num_reads=num_reads)
+ self.create_variables_mapping(sampleset)
+ return sampleset
+
+ def solve(self, matrices: Tuple, strength: float = 10) -> List:
+ """Solve the system of equations
+
+ Args:
+ matrices (Tuple): Matrices of the system
+ strength (float, optional): Strength of the susbtitution. Defaults to 10.
+
+ Returns:
+ List: Solution of the system
+ """
+
+ # create the bqm
+ self.qubo_dict = self.create_bqm(matrices, strength=strength)
+
+ # sample the bqm
+ self.sampleset = self.sample_bqm(
+ self.qubo_dict, num_reads=self.options["num_reads"]
+ )
+ self.lowest_sol = self.sampleset.lowest()
+
+ # sample the systen and return the solution
+ return self.decode_solution(self.lowest_sol.record[0][0])
+
+ def extract_all_variables(self):
+ """Extracs all the variable names and expressions"""
+ self.all_vars = []
+ self.all_expr = []
+ for var in self.x:
+ expr = [(str(k), v) for k, v in var.as_coefficients_dict().items()]
+ self.all_expr.append(expr)
+ self.all_vars += [str(k) for k in var.as_coefficients_dict().keys()]
+
+ def create_polynom(self, x: np.ndarray) -> Poly:
+ """Creates the polynom from the matrices
+
+ Args:
+ x (np.ndarray):
+
+ Returns:
+ Poly: a polynom
+ """
+ self.num_equations = self.matrices[1].shape[0]
+ polynom = Matrix([0] * self.num_equations)
+
+ for imat, matrix in enumerate(self.matrices):
+
+ for idx, val in zip(matrix.coords.T, matrix.data):
+ if imat == 0:
+ polynom[idx[0]] += val
+ else:
+ polynom[idx[0]] += val * x[idx[1:]].prod()
+ return polynom
+
+ def create_qubo_matrix(
+ self, x: np.ndarray, strength: float = 10, prec: Union[float, None] = None
+ ) -> dimod.BQM:
+ """Create the QUBO dictionary requried by dwave solvers
+ to solve the polynomial equation P0 + P1 x + P2 x^2 + ... = 0
+
+ Args:
+ x (np.ndarray): x vector
+ strength (int, optional): strength of the substitution. Defaults to 10.
+ prec (floa, optional):precision. Defaults to None.
+
+ Returns:
+ dimod.BQM: Binary quadratic model
+ """
+ polynom = self.create_polynom(np.array(x))
+
+ polynom = polynom.T @ polynom
+
+ polynom = polynom[0]
+ polynom = polynom.expand()
+ polynom = polynom.as_ordered_terms()
+ polynom = self.create_poly_dict(polynom, prec=prec)
+ bqm = dimod.make_quadratic(polynom, strength=strength, vartype=dimod.BINARY)
+
+ return bqm
+
+ @staticmethod
+ def create_poly_dict(polynom: Poly, prec: Union[float, None] = None) -> Dict:
+ """Creates a dict from the sympy polynom
+
+ Args:
+ polynom (Poly): polynom of the system
+ prec (float,None): precision of the terms to keep
+
+ Returns:
+ Dict: dictionary represetnation of the polynom
+ """
+ out = dict()
+
+ for term in polynom:
+ m = term.args
+ if len(m) == 0:
+ continue
+
+ if len(m) == 2:
+ varname = str(m[1])
+ tmp = varname.split("**")
+ if len(tmp) == 1:
+ exponent = 1
+ else:
+ varname, exponent = tmp
+ exponent = int(exponent)
+ key = (varname,) * exponent
+
+ elif len(m) > 2:
+ key = tuple()
+ for mi in m[1:]:
+ mi = str(mi)
+ tmp = mi.split("**")
+ if len(tmp) == 1:
+ key += (tmp[0],)
+ if len(tmp) == 2:
+ varname = tmp[0]
+ exp = int(tmp[1])
+ key += (varname,) * exp
+
+ 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
+
+ def decode_solution(self, data: np.ndarray) -> np.ndarray:
+ """Decodes the solution vector
+
+ Args:
+ data (np.ndarray): sampled values
+
+ Returns:
+ np.ndarray: numerical values for the solution
+ """
+ return self.mixed_solution_vectors.decode_solution(data[self.index_variables])
+
+ def create_variables_mapping(self, sol: dimod.SampleSet):
+ """generates the index of variables in the solution vector
+
+ Args:
+ sol (dimod.Sampleset): sampleset from the sampler
+ """
+ # extract the data of the original variables
+ self.index_variables, self.mapped_variables = [], []
+ for ix, s in enumerate(sol.variables):
+ if s in self.all_vars:
+ self.index_variables.append(ix)
+ self.mapped_variables.append(s)
+
+ def compute_energy(self, vector: np.ndarray, bqm: dimod.BQM) -> Tuple:
+ """Compue the QUBO energy of the vector containing the solution of the initial problem
+
+ Args:
+ vector (np.ndarray): solution of the problem
+ """
+ closest_vec = []
+ bin_encoding_vector = []
+ encoded_variables = []
+ for val, svec in zip(vector, self.mixed_solution_vectors.encoded_reals):
+ closest_val, bin_encoding = svec.find_closest(val)
+ closest_vec.append(closest_val)
+ bin_encoding_vector += bin_encoding
+ encoded_variables += [str(sv) for sv in svec.variables]
+
+ bqm_input_variables = {}
+ for v in bqm.variables:
+ if v in encoded_variables:
+ idx = encoded_variables.index(v)
+ bqm_input_variables[v] = bin_encoding_vector[idx]
+ else:
+ var_tmp = v.split("*")
+ itmp = 0
+ for vtmp in var_tmp:
+ idx = encoded_variables.index(vtmp)
+ val = bin_encoding_vector[idx]
+ if itmp == 0:
+ bqm_input_variables[v] = val
+ itmp = 1
+ else:
+ bqm_input_variables[v] *= val
+
+ return (
+ closest_vec,
+ (bin_encoding_vector, encoded_variables),
+ bqm_input_variables,
+ ), bqm.energy(bqm_input_variables)
diff --git a/qubols/solution_vector.py b/qubols/solution_vector.py
index 251343a..c673a25 100644
--- a/qubols/solution_vector.py
+++ b/qubols/solution_vector.py
@@ -1,5 +1,6 @@
from sympy.matrices import Matrix
import numpy as np
+from copy import deepcopy
from .encodings import RangedEfficientEncoding
@@ -37,7 +38,7 @@ def create_encoding(self):
list[RealEncoded]:
"""
encoded_reals = []
- is_ranged_encoding = (self.encoding == RangedEfficientEncoding)
+ is_ranged_encoding = self.encoding == RangedEfficientEncoding
for i in range(self.size):
var_base_name = self.base_name + "_%03d" % (i + 1)
if is_ranged_encoding:
@@ -65,4 +66,43 @@ def decode_solution(self, data):
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) + np.array(self.offset)
+ return np.array(sol) # + np.array(self.offset)
+
+
+class SolutionVector_V2(SolutionVector):
+
+ def __init__(self, size, encoding, base_name="x"):
+ """_summary_
+
+ Args:
+ size (_type_): _description_
+ encoding (_type_): _description_
+ base_name (str)
+
+ Returns:
+ _type_: _description_
+ """
+
+ self.size = size
+ self.base_name = base_name
+ self.encoding = encoding
+ self.nqbit = encoding.nqbit
+ self.offset = encoding.offset
+ 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)
+ x = deepcopy(self.encoding)
+ x.set_var_base_name(var_base_name)
+ x.variables = x.create_variable()
+ encoded_reals.append(x)
+ return encoded_reals