Commit 4feb1e4b by Abhishek

.

parent f7b7d79c
 ... ... @@ -18,7 +18,7 @@ }, { "cell_type": "code", "execution_count": 1, "execution_count": null, "metadata": { "nbgrader": { "grade": false, ... ... @@ -26,17 +26,7 @@ "solution": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Available frameworks:\n", "Qiskit\n", "D-Wave Ocean\n" ] } ], "outputs": [], "source": [ "%run -i \"assignment_helper_QML.py\"\n", "%matplotlib inline" ... ... @@ -63,7 +53,7 @@ "The aim of MaxCut is to maximize the number of edges (yellow lines) in a graph that are \"cut\" by\n", "a given partition of the vertices (blue circles) into two sets (see figure below).\n", "\n", "" "" ] }, { ... ... @@ -74,11 +64,7 @@ "\n", "\\begin{align}C(z) = \\sum_{\\alpha=1}^{m}C_\\alpha(z),\\end{align}\n", "\n", "where $C$ counts the number of edges cut. $C_\\alpha(z)=1$ if $z$ places one vertex from the $\\alpha^\\text{th}$ edge in set $A$ and the other in set $B$, and $C_\\alpha(z)=0$ otherwise. Finding a cut which yields the maximum possible value of $C$ is an NP-complete problem, so our best hope for a polynomial-time algorithm lies in an approximate optimization. In the case of MaxCut, this means finding a partition $z$ which yields a value for $C(z)$ that is close to the maximum possible value.\n", "\n", "We can represent the assignment of vertices to set $A$ or $B$ using a bitstring, $z=z_1...z_n$ where $z_i=0$ if the $i^\\text{th}$ vertex is in $A$ and $z_i = 1$ if it is in $B$. For instance, in the situation depicted in the figure above the bitstring representation is $z=0101\\text{,}$ indicating that the $0^{\\text{th}}$ and $2^{\\text{nd}}$ vertices are in $A$ while the $1^{\\text{st}}$ and $3^{\\text{rd}}$ are in $B$. This assignment yields a value for the objective function (the number of yellow lines cut) $C=4$, which turns out to be the maximum cut. In the following sections, we will represent partitions using computational basis states and use PennyLane to rediscover this maximum cut.\n", "\n", "

Note

In the graph above, $z=1010$ could equally well serve as the maximum cut.

" "where $C$ counts the number of edges cut. $C_\\alpha(z)=1$ if $z$ places one vertex from the $\\alpha^\\text{th}$ edge in set $A$ and the other in set $B$, and $C_\\alpha(z)=0$ otherwise. Finding a cut which yields the maximum possible value of $C$ is an NP-complete problem, so our best hope for a polynomial-time algorithm lies in an approximate optimization. In the case of MaxCut, this means finding a partition $z$ which yields a value for $C(z)$ that is close to the maximum possible value.\n" ] }, { ... ... @@ -124,7 +110,7 @@ }, { "cell_type": "code", "execution_count": 2, "execution_count": null, "metadata": { "collapsed": false, "jupyter": { ... ... @@ -155,7 +141,7 @@ }, { "cell_type": "code", "execution_count": 11, "execution_count": null, "metadata": { "collapsed": false, "jupyter": { ... ... @@ -196,7 +182,7 @@ }, { "cell_type": "code", "execution_count": 12, "execution_count": null, "metadata": { "collapsed": false, "jupyter": { ... ... @@ -222,7 +208,7 @@ }, { "cell_type": "code", "execution_count": 13, "execution_count": null, "metadata": { "collapsed": false, "jupyter": { ... ... @@ -250,7 +236,7 @@ }, { "cell_type": "code", "execution_count": 14, "execution_count": null, "metadata": { "collapsed": false, "jupyter": { ... ... @@ -286,44 +272,30 @@ "source": [ "## Optimization ##\n", "\n", "Finally, we optimize the objective over the angle parameters $\\boldsymbol{\\gamma}$ (params[0]) and $\\boldsymbol{\\beta}$ (params[1]) and then sample the optimized circuit multiple times to yield a distribution of bitstrings. One of the optimal partitions ($z=0101$ or $z=1010$) should be the most frequently sampled bitstring. We perform a maximization of $C$ by minimizing $-C$, following the convention that optimizations are cast as minimizations in PennyLane.\n", "Finally, we optimize the objective over the angle parameters $\\boldsymbol{\\gamma}$ (params[0]) and $\\boldsymbol{\\beta}$ (params[1]) and then sample the optimized circuit multiple times to yield a distribution of bitstrings. One of the optimal partitions should be the most frequently sampled bitstring. We perform a maximization of $C$ by minimizing $-C$, following the convention that optimizations are cast as minimizations in PennyLane.\n", "\n" ] }, { "cell_type": "code", "execution_count": 20, "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "p=1\n", "Objective after step 5: 2.7870528\n", "Objective after step 10: 2.9983800\n", "Optimized (gamma, beta) vectors:\n", "[[-0.78539768]\n", " [-1.1923295 ]]\n", "Most frequently sampled bit string is: 1010\n" ] } ], "outputs": [], "source": [ "n_layers = 1 # Enter the layes you want\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "n_layers = 1 # Enter the layes you want\n", "\n", "\n", "print(\"\\np={:d}\".format(n_layers))\n", "\n", "# initialize the parameters near zero\n", "init_params = 0.01 * np.random.rand(2, n_layers)\n", "\n", "# minimize the negative of the objective function\n", "def objective(params):\n", " gammas = params[0]\n", ... ... @@ -332,18 +304,34 @@ " for edge in graph:\n", " # objective for the MaxCut problem\n", " neg_obj -= 0.5 * (1 - circuit(gammas, betas, edge=edge, n_layers=n_layers))\n", " return neg_obj\n", " return neg_obj\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# initialize optimizer: Adagrad works well empirically\n", "opt = qml.AdagradOptimizer(stepsize=0.5)\n", "opt = qml.AdagradOptimizer(stepsize=0.1)\n", "\n", "# optimize parameters in objective\n", "params = init_params\n", "params = 0.01 * np.random.rand(2, n_layers)\n", "steps = 10\n", "for i in range(steps):\n", " params = opt.step(objective, params)\n", " if (i + 1) % 5 == 0:\n", " print(\"Objective after step {:5d}: {: .7f}\".format(i + 1, -objective(params)))\n", " print(\"Objective after step {:5d}: {: .7f}\".format(i + 1, -objective(params)))\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# sample measured bitstrings 100 times\n", "bit_strings = []\n", ... ... @@ -359,50 +347,25 @@ "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the case where we set n_layers=2, we recover the optimal\n", "objective function $C=4$\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Plotting the results\n", "--------------------\n", "We can plot the distribution of measurements obtained from the optimized circuits. As\n", "expected for this graph, the partitions 0101 and 1010 are measured with the highest frequencies,\n", "and in the case where we set n_layers=2 we obtain one of the optimal partitions with 100% certainty.\n", "\n" "We can plot the distribution of measurements obtained from the optimized circuits." ] }, { "cell_type": "code", "execution_count": 18, "execution_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!