diff --git a/data/t01.dat b/data/t01.dat new file mode 100644 index 0000000..aa8dfdd --- /dev/null +++ b/data/t01.dat @@ -0,0 +1,14 @@ +6 +12 +0 0 1 0 +1 0 2 0 +2 0 3 0 +3 0 4 0 +4 0 5 0 +5 1 2 1 +6 1 4 1 +7 1 5 100 +8 2 3 100 +9 2 5 1 +10 3 4 100 +11 3 5 1 diff --git a/doc/document.tex b/doc/document.tex index 01754da..e9051ea 100644 --- a/doc/document.tex +++ b/doc/document.tex @@ -6,20 +6,33 @@ \usepackage{amsmath} \usepackage{amsthm} \usepackage{amssymb} - +\usepackage{multirow} +\numberwithin{equation}{section} \title{Algorithmics WS13/14, Programming Exercise} -\author{Dino Rossegger, Markus Scherer} +\author{Dino Rossegger \emph{0926471}\\ Markus Scherer \emph{1028046}} \date{\today} \begin{document} \maketitle -\section{MTZ Formulation} -Let $x_{ij}=1$ if $e_{ij}\in E$ is in the Spanning Tree, else $x_{ij}=0$. The objective function is the same as in the other formulations +\section{General} +A artificial root vertex $0$ was introduced in the graphs which edges going to all other nodes and the cost function $c_{0j}=0\quad \forall j\in V$. Since the formulations work with directed graphs for every undirected edge $e$, two new edges where introduced, $e_{ij}$ and $e_{ji}$ denoting the corresponding arcs. +For all Formulations the same objective function was used. \begin{equation} \min{\sum_i \sum_{j\not=i} c_{ij}x_{ij}} +\end{equation} +$c_{ij}$ is denoting the cost of the arc and $x_{ij}$ being $1$ if the arc is chosen or $0$ otherwise. +Therefore a constraint limiting the values $x$ can take was used. +\begin{equation} + x_{ij} \in \{0,1\} \qquad \forall (i,j) +\end{equation} +To tighten the constraints, an additional variable $v_i$ was introduced, being $1$ if vertex $i$ is selected and $0$ otherwise. +\begin{equation} + v_i \in\{0,1\} \qquad \forall i=0,\dots,n \end{equation} + +\section{MTZ Formulation} For the Miller-Tucker-Zemlin formulation an order $u_i$ is introduced, it ensures that there is no cycle. \begin{equation} - kx_{ij} + u_i \leq u_j + (k-1) \quad \forall i,j=0,\dots,n +x_{ij} + u_i \leq u_j + k*(1-x_{ij}) \qquad \forall (i,j) \end{equation} The start vertex must be the artificial vertex $0$. \begin{equation} @@ -27,7 +40,7 @@ \section{MTZ Formulation} \end{equation} There must be exactly one arc from the artificial vertex $0$ to any other vertex in the tree. \begin{equation} - \sum_{j>0} x_{0j} = 1 + \sum_{j\geq1} x_{0j} = 1 \end{equation} $u_i$ must be between $0$ and $k$ since $k$ vertices are in the tree. \begin{equation} @@ -35,16 +48,15 @@ \section{MTZ Formulation} \end{equation} By the tree property $n=m+1$ the number of edges in the tree must be $k$. \begin{equation} - \sum_{i\geq0} \sum_{j\geq0,j\not =i} x_{ij} = k + \sum_{(i,j)} x_{ij} = k \end{equation} Since there is an order, we are talking about arcs and for every vertex there must be at most one incoming arc. \begin{equation} - \sum_{i>0} x_{ij}\leq 1 \quad \forall j=1,\dots,n + \sum_{i\geq 1} x_{ij}\leq 1 \qquad \forall j=1,\dots,n \end{equation} -Let $v_i=1$ if vertex $i \in k-MST$ and $0$ otherwise. -The number of vertices in the tree must be $k$. +The number of vertices in the tree (excluding the start node) must be $k$. \begin{equation} - \sum_{i>0}v_i=k + \sum_{i\geq 1}v_i=k \end{equation} Only $v_i \in k-MST$ must have $u_i>0$. \begin{equation} @@ -55,6 +67,130 @@ \section{MTZ Formulation} x_{ij} &\leq u_i \\ x_{ij} &\leq u_j \end{align} -\end{document} +The sum of orders $u$ must be exactly $\frac{k(k+1)}{2}$. +\begin{equation} + \sum_{j \geq 0} u_{j}=\frac{k(k+1)}{2} \\ +\end{equation} +Whenever an arc is chosen, the corresponding arc in the other direction cannot be chosen. +\begin{equation} + x_{ij} + x_{ij}\leq 1 \\ +\end{equation} + + +\section{SCF Formulation} +A commodity is introduced. This commodity can flow along each +arc and results thus in the following decision variables: +\begin{equation} + f_{ij} \qquad \forall (i,j) +\end{equation} +There must be $k$ arcs in the tree (including arc from $0$) +\begin{equation} + \sum_{(i,j)} x_{ij} = k +\end{equation} +The number of vertices in the tree must be $k$ ($0$ not included) +\begin{equation} + \sum_{i \geq 1}v_i =k \\ +\end{equation} +There must be exactly $1$ arc going out of $0$ in the solution +\begin{equation} + \sum_{j \geq 1} x_{0j}=1\\ +\end{equation} +If an arc is selected, vertices incident to it must be selected too +\begin{equation} + x_{ij} \leq v_i\\ +\end{equation} +\begin{equation} + x_{ij} \leq v_j\\ +\end{equation} +There can be either a forward or a backward arc in the solution, not both. +\begin{equation} + v_i + x_{ij} + x_{ji} \leq v_j + 1\\ +\end{equation} +The flow must be at most $k$, and at least $0$ +\begin{equation} + 0 \leq f_{ij} \leq k\\ +\end{equation} +Exactly $k$ units of flow are sent out from node $0$. +\begin{equation} + \sum_{j>0} f_{0j}=k \\ +\end{equation} +Every vertex in the solution consumes $1$ flow. +\begin{equation} + \sum_{(i,j)} f_{ij} - \sum_{(j,i)} f_{ji} = v_j \qquad \forall j=1,\dots,n\\ +\end{equation} +The flow going through an arc can be at most $k$. +\begin{equation} + f_{ij}\leq kx_{ij} +\end{equation} +\section{MCF Formulation} +For every node a different commodity is introduced. These commodities can flow along each +arc and result thus in the following decision variables: +\begin{equation} + f_{ij}^l \in \{0,1\} \qquad \forall (i,j) \quad \forall l = 1,\dots, n\\ +\end{equation} + +Most of the constraints are the same as in the single commodity flow formulation. +\begin{align} + \sum_{(i,j)} x_{ij} = k\\ + \sum_{i\geq1}v_i =k \\ + \sum_{j\geq1} x_{0j}=1\\ + \sum_{i\geq1} x_{i0}=0\\ + x_{ij} \leq v_i\\ + x_{ij} \leq v_j\\ + v_i + x_{ij} + x_{ji} \leq v_j + 1 +\end{align} +The commodities of type $l$ going out of vertex $0$ must be exactly $v_l$ (only commodities of selected nodes are sent out) +and the sum of all sent from $0$ commodities must be $k$. +\begin{equation} + \sum_{j\geq1} f_{0j}^l = v_l \qquad \forall l= 1,\dots, n +\end{equation} +\begin{equation} + \sum_{l=1}^n \sum_{(0,j)} f_{0j}^l = k\\ +\end{equation} +The sum of flows on commodity $l$ flowing into vertex $l$ is at most $v_l$. +\begin{equation} +\sum_{i,i\not =l} f_{il}^l \leq v_l \qquad \forall l = 1,\dots,n\\ +\end{equation} +If there is a flow on an arc, the arc must be selected. +\begin{equation} +0\leq f_{ij}^l \leq x_{ij} \qquad \forall (i,j) \quad \forall l = 0,\ldots,n +\end{equation} +All vertices which are not the target of the commodity can not consume a flow. +\begin{equation} +\sum_{i,i\not = j}f_{ij}^l - \sum_{i,i\not = j} f_{ji}^l =0 \qquad \forall j, l = 1,\dots,n \quad j\not =l \\ +\end{equation} +$v_l$ cannot send out flow of it's own commodity. +\begin{equation} +\sum_{j\not=l} f_{lj}^l =0\\ +\end{equation} +If there is flow incoming to vertex $l$ on its commodity, the vertex must be selected +\begin{equation} +\sum_{(i,l)} f_{il}^l - v_l=0 \qquad \forall l = 1,\dots,n \quad \forall i = 1,\dots,n\\ +\end{equation} +The sum of incoming flows matching a node, over all commodities, must be $k$ +\begin{equation} + \sum_{l=1}^n \sum_{(i,l)} f_{i,l}^l = k\\ +\end{equation} + +% \sum_{(0,j)} f_{0,j}^l -v_l = 0 \quad \forall l\in N\setminus\{0\}\\ +If an arc is selected, there must be a flow on the arc. +\begin{equation} +x_{ij} \leq \sum_{l=1}^n f_{ij}^l +\end{equation} + +\section{Results} + +SCF is the only formulation that solves all instances. MTZ seems to have advantages over SCF with +smaller $k$-values but fails to solve the last configuration (after several hours the laptop +used for the benchmarks became unresponsive, possibly due overheating issues). MTZ also uses more +branch-and-bound-nodes. + +Our MCF-Formulation is not able to solve all instances (for \emph{g06} it fails to prove optimality, +in the time we granted to it, although the optimal value is found, for \emph{g07} and \emph{g08} the +program crashes after exhausting the memory of the test computer (8GB)). + +\input{results.tex} + +\end{document} diff --git a/doc/results.tex b/doc/results.tex new file mode 100644 index 0000000..208b8c9 --- /dev/null +++ b/doc/results.tex @@ -0,0 +1,30 @@ + +\begin{tabular}{ l l r r r r r r r} + \multicolumn{2}{c}{} & \multicolumn{2}{c}{\textbf{MTZ}} & \multicolumn{2}{c}{\textbf{SCF}} & \multicolumn{2}{c}{\textbf{MCF}} & \textbf{Optimal Value}\\ + & k & time [s] & nodes & times [s] & nodes & time [s] & nodes & \\ + \hline + \multirow{2}{*}{g01} & 2 & 0.01 & 0 & 0.00 & 0 & 0.04 & 0 & 46 \\ + & 5 & 0.02 & 0 & 0.02 & 0 & 0.07 & 0 & 477 \\ + \hline + \multirow{2}{*}{g02} & 4 & 0.05 & 0 & 0.03 & 0 & 0.22 & 0 & 373 \\ + & 10 & 0.07 & 0 & 0.05 & 0 & 0.15 & 0 & 1390 \\ + \hline + \multirow{2}{*}{g03} & 10 & 0.18 & 36 & 1.59 & 1725 & 1.37 & 0 & 725 \\ + & 25 & 1.55 & 1896 & 0.13 & 0 & 2.38 & 0 & 3074 \\ + \hline + \multirow{2}{*}{g04} & 14 & 0.53 & 68 & 2.55 & 478 & 16.56 & 97 & 909 \\ + & 35 & 2.70 & 604 & 0.36 & 0 & 9.36 & 0 & 3292 \\ + \hline + \multirow{2}{*}{g05} & 20 & 1.86 & 621 & 0.35 & 0 & 14.73 & 0 & 1235 \\ + & 50 & 7.79 & 6681 & 0.52 & 0 & 26.59 & 0 & 4898 \\ + \hline + \multirow{2}{*}{g06} & 40 & 80.06 & 24464 & 43.21 & 1074 & \textemdash & \textemdash & 2068 \\ + & 100 & 163.29 & 122401 & 7.84 & 2825 & \textemdash & \textemdash & 6705 \\ + \hline + \multirow{2}{*}{g07} & 60 & 25.35 & 2035 & 23.96 & 0 & \textemdash & \textemdash & 1335 \\ + & 150 & 93.56 & 4237 & 26.60 & 98 & \textemdash & \textemdash & 4534 \\ + \hline + \multirow{2}{*}{g08} & 80 & 16.93 & 760 & 75.47 & 477 & \textemdash & \textemdash & 1620 \\ + & 200 & \textemdash & \textemdash & 117.59 & 477 & \textemdash & \textemdash & 5787 \\ + \hline +\end{tabular} diff --git a/src/kMST_ILP.cpp b/src/kMST_ILP.cpp index 643f929..030d5c9 100644 --- a/src/kMST_ILP.cpp +++ b/src/kMST_ILP.cpp @@ -1,7 +1,7 @@ #include "kMST_ILP.h" kMST_ILP::kMST_ILP( Instance& _instance, string _model_type, int _k ) : - instance( _instance ), model_type( _model_type ), k( _k ), x(env,instance.n_edges) + instance( _instance ), model_type( _model_type ), k( _k ), x(env,2*instance.n_edges) { n = instance.n_nodes; m = instance.n_edges; @@ -27,7 +27,7 @@ void kMST_ILP::solve() // build model cplex = IloCplex( model ); // export model to a text file - //cplex.exportModel( "model.lp" ); + cplex.exportModel( "model.lp" ); // set parameters setCPLEXParameters(); @@ -39,8 +39,9 @@ void kMST_ILP::solve() cout << "Branch-and-Bound nodes: " << cplex.getNnodes() << "\n"; cout << "Objective value: " << cplex.getObjValue() << "\n"; cout << "CPU time: " << Tools::CPUtime() << "\n\n"; - printX(); + //printX(); cout << "Solution is " << (isTree() ? "valid" : "invalid") << "\n\n"; + cplex.writeSolution("solution.lp"); } catch( IloException& e ) { cerr << "kMST_ILP: exception " << e << "\n"; @@ -65,16 +66,501 @@ void kMST_ILP::setCPLEXParameters() void kMST_ILP::modelSCF() { - // ++++++++++++++++++++++++++++++++++++++++++ - // TODO build single commodity flow model - // ++++++++++++++++++++++++++++++++++++++++++ + //x + for(int i=0;i f(env,n); + //IloIntVar f[n][2*m]; + for(int l=1;l::iterator it=instance.incidentEdges.at(j).begin();it!=instance.incidentEdges.at(j).end();it++){ + if(instance.edges.at(*it).v1==j && j!=l){ + co33+=f[l][*it+m]; + co33-=f[l][*it]; + } + else if(instance.edges.at(*it).v2==j && j!=l){ + co33+=f[l][*it]; + co33-=f[l][*it +m ]; + } + else + dontadd=true; + + } + if(!dontadd) { + model.add(co33==0); + } + co33.end(); + + } + } + + //(4.14) + for (int l=1;l::iterator it=instance.incidentEdges.at(l).begin();it!=instance.incidentEdges.at(l).end();it++){ + if(instance.edges.at(*it).v1==l){ + co34+=f[l][*it]; + } + else if(instance.edges.at(*it).v2==l){ + co34+=f[l][*it+m]; + } + } + model.add(co34 == 0); + co34.end(); + } + + +// //() +// for (int l=1;l::iterator it=instance.incidentEdges.at(l).begin();it!=instance.incidentEdges.at(l).end();it++){ + if(instance.edges.at(*it).v1==l && instance.edges.at(*it).v2!=l){ + co+=f[l][*it+m]; + } + else if(instance.edges.at(*it).v2==l && instance.edges.at(*it).v1!=l){ + co+=f[l][*it]; + } + } + } + model.add(co==k); + co.end(); + + //(4.10) + IloExpr co_35(env); + for (int l=1;l::iterator it=instance.incidentEdges.at(0).begin();it!=instance.incidentEdges.at(0).end();it++){ + co+=f[l][*it]; + } + model.add(co - v[l]==0); + co.end(); + } + //(4.17) + for(int k=0;k=x_ij); + model.add(co_1>=x_ji); + co_0.end(); + co_1.end(); + + x_ij.end(); + x_ji.end(); + } + + //cout << model; } void kMST_ILP::modelMTZ() @@ -84,18 +570,25 @@ void kMST_ILP::modelMTZ() stringstream myname; myname << "x_" << instance.edges.at(i).v1 << "," <::iterator it=instance.incidentEdges.at(i).begin();it != instance.incidentEdges.at(i).end();++it){ + if(instance.edges.at(*it).v2==i) + co7+=x[*it]; + else + co7+=x[*it+m]; } model.add(co7 <= 1); co7.end(); } - //(8) + //(2.7) IloExpr co8(env); - for(int i=1;i