diff --git a/heldAndKarp.ipynb b/heldAndKarp.ipynb index bb231199849c5299d575ec618fe663e43d1ba451..a03a28fe10b71ae9a41766d20eed218c8888dd0f 100644 --- a/heldAndKarp.ipynb +++ b/heldAndKarp.ipynb @@ -53,7 +53,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": {}, "outputs": [ { @@ -76,9 +76,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "checkTermination (generic function with 2 methods)" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "function checkTermination(m, verbose = true)\n", " if !( \n", @@ -100,12 +111,42 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "display_S (generic function with 2 methods)" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "function display(S, W = Nothing)\n", - " gplot(Graph(S), nodelabel=1:size(S,1))\n", + "# Graph display function\n", + "# S and W are assumed to be square matrices\n", + "# S the adjacency matrix of a graph\n", + "# W the weights of its edges\n", + "function display_S(S, W = Nothing)\n", + " edgelabel = []\n", + " n = size(S,1)\n", + " if W != nothing\n", + " m = size(W, 1)\n", + " if m != n\n", + " error(\"display_S : S and W don't match ; S is of size \", n, \", W of size \", m)\n", + " end\n", + " for i in 1:n\n", + " for j in i:n\n", + " if X[i, j] == 1\n", + " push!(edgelabel, W[i, j])\n", + " end\n", + " end\n", + " end\n", + " end\n", + " gplot(Graph(S), nodelabel=1:n, edgelabel = edgelabel)\n", "end" ] }, @@ -128,7 +169,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 6, "metadata": { "tags": [] }, @@ -220,10 +261,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "IPM (generic function with 1 method)" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ + "# Integer Programming Master problem\n", + "# C is a vector such that C[t] = dot(c, x^t) for t in 1:T_1\n", + "# where T_1 is the number of columns of the master problem\n", + "# D[i, t] is d_i^t the degree of vertex i in column number t\n", "function IPM(C, D)\n", " ipm = Model(Cbc.Optimizer)\n", " set_silent(ipm)\n", @@ -291,7 +347,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In (LPM) there is a column $ ( c^T x^t , d_1^t , \\ldots , d_n^t , 1 )^T$ for every $x^t \\in X^1 \\ (t = 1, \\ldots, T_1)$ \n", + "In (LPM) there is a column $ ( c^{\\dagger} x^t , d_1^t , \\ldots , d_n^t , 1 )^{\\dagger}$ for every $x^t \\in X^1 \\ (t = 1, \\ldots, T_1) $ ($\\dagger$ means transpose in this context) \n", + "\n", "The second equation is a convexity constraint\n", "\n", "Associating the second equation with dual variable $\\mu$ and the degree constraints with dual variables $\\{\\pi_i\\}_{i=1}^m$ the dual of (LPM) is\n", @@ -299,7 +356,7 @@ "$$\\text{(DM)} \\quad\n", "\\begin{array}{r l}\n", "\\max_{\\mu, \\pi} & \\sum_{i=1}^m 2 \\pi_i + \\mu \\\\\n", - "\\text{s.t.} & \\pi^T d^t + \\mu \\leq c^T x^t \\quad (t = 1 \\ldots T_1)\n", + "\\text{s.t.} & \\pi^{\\dagger} d^t + \\mu \\leq c^{\\dagger} x^t \\quad (t = 1 \\ldots T_1)\n", "\\end{array}$$" ] }, @@ -309,6 +366,11 @@ "metadata": {}, "outputs": [], "source": [ + "# Dual Master problem\n", + "# C is a vector such that C[t] = sum_e∈E(c_e * x_e^t) for t in 1:T_1\n", + "# where T_1 is the number of columns of the master problem\n", + "# D[i, t] is d_i^t the degree of vertex i in column number t\n", + "\n", "function DM(C, D)\n", " dm = Model(Cbc.Optimizer)\n", " set_silent(dm)\n", @@ -485,9 +547,9 @@ "source": [ "## Held and Karp algorithm - attempt 1\n", "\n", - "This is the part where we implement the Held and Karp algorithm as described in J.E. Mitchell's slides using Kruskal's algorithm to solve the minimum spanning tree problem.\n", + "This is the part where we implement the Held and Karp algorithm as described in J.E. Mitchell's slides using Kruskal's algorithm to solve the minimum spanning tree problem. Since the goal of this algorithm is allegedly to provide a new column to the master problem, there is no guarantee that it gives an optimal solution.\n", "\n", - "However this approach seems to be flawed as the example is easily solved, however the exercise seems to alternate between two identical states. \n", + "Even though this approach seems to be flawed, the example is easily solved ; however the exercise seems to alternate between two identical states. \n", "This may be due to the update rule of $\\lambda$, results may vary by modifying it." ] }, @@ -739,7 +801,7 @@ "Whilst column generation based techniques work well on wide graphs, on smaller ones we may want to use a different method.\n", "\n", "Here we use dynamical programming to implement the Bellman-Held-Karp algorithm. \n", - "It works well on small graph, but scales terribly because of its exponential complexity $O(2^n n^2)$ in time (and $O(2^n n)$ in space)" + "It works well on small graphs, but scales terribly because of its exponential complexity $O(2^n n^2)$ in time (and $O(2^n n)$ in space)." ] }, { @@ -887,15 +949,15 @@ ], "metadata": { "kernelspec": { - "display_name": "Julia 1.4.2", + "display_name": "Julia 1.5.3", "language": "julia", - "name": "julia-1.4" + "name": "julia-1.5" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.4.2" + "version": "1.5.3" } }, "nbformat": 4,