eg_min_cut.ex.c

00001 /* EGlib "Efficient General Library" provides some basic structures and
00002  * algorithms commons in many optimization algorithms.
00003  *
00004  * Copyright (C) 2005 Daniel Espinoza and Marcos Goycoolea.
00005  * 
00006  * This library is free software; you can redistribute it and/or modify it
00007  * under the terms of the GNU Lesser General Public License as published by the
00008  * Free Software Foundation; either version 2.1 of the License, or (at your
00009  * option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful, but 
00012  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
00013  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
00014  * License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this library; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
00019  * */
00020 /** @file
00021  * @ingroup EGalgMinCut */
00022 /** @addtogroup EGalgMinCut */
00023 /** @{ */
00024 #include "eg_min_cut.h"
00025 #include "eg_timer.h"
00026 #include <getopt.h>
00027 #include <stdio.h>
00028 static char *file_name = 0;
00029 static unsigned int lvl = 5;
00030 /* ========================================================================= */
00031 /** @brief display usage of this program */
00032 static inline void mc_usage (char **argv)
00033 {
00034   fprintf (stderr, "Usage: %s [options]\n", argv[0]);
00035   fprintf (stdout, "Options:\n");
00036   fprintf (stdout, "     -l n   level of padberg-rinaldi shrinking (0-5).\n");
00037   fprintf (stdout, "     -f n   file name.\n");
00038 }
00039 
00040 /* ========================================================================= */
00041 /** @brief structure to store a set of cuts */
00042 typedef struct mc_all_cuts_t
00043 {
00044   unsigned int sz;
00045   unsigned int max_sz;
00046   EGlpNum_t *cut_val;
00047   unsigned int *cut_sz;
00048   unsigned int **cut;
00049 }
00050 mc_all_cuts_t;
00051 
00052 /* ========================================================================= */
00053 /** @brief call-back function to store all cuts fund during the execution of
00054  * the min-cut algorithm. */
00055 int mc_store_cuts (EGlpNum_t value,
00056                    const unsigned int c_sz,
00057                    const unsigned int *const cut,
00058                    void *data)
00059 {
00060   mc_all_cuts_t *cuts = (mc_all_cuts_t *) data;
00061   /* of the cut pool is too small, enlarge it */
00062   if (cuts->sz == cuts->max_sz)
00063   {
00064     unsigned int *l_cut_sz,
00065     **l_cut;
00066     EGlpNum_t *l_cut_val;
00067     cuts->max_sz += 100;
00068     l_cut_sz = EGsMalloc (unsigned int,
00069                           cuts->max_sz);
00070     l_cut = EGsMalloc (unsigned int *,
00071                        cuts->max_sz);
00072     l_cut_val = EGsMalloc (EGlpNum_t, cuts->max_sz);
00073     if (cuts->sz)
00074     {
00075 
00076       memcpy (l_cut_sz, cuts->cut_sz, sizeof (unsigned int) * cuts->sz);
00077       memcpy (l_cut, cuts->cut, sizeof (unsigned int *) * cuts->sz);
00078       memcpy (l_cut_val, cuts->cut_val, sizeof (EGlpNum_t) * cuts->sz);
00079       EGfree (cuts->cut);
00080       EGfree (cuts->cut_sz);
00081       EGfree (cuts->cut_val);
00082     }
00083     cuts->cut_sz = l_cut_sz;
00084     cuts->cut = l_cut;
00085     cuts->cut_val = l_cut_val;
00086   }
00087   /* now we copy the new cut */
00088   EGlpNumInitVar (cuts->cut_val[cuts->sz]);
00089   EGlpNumCopy (cuts->cut_val[cuts->sz], value);
00090   cuts->cut_sz[cuts->sz] = c_sz;
00091   cuts->cut[cuts->sz] = EGsMalloc (unsigned int,
00092                                    c_sz);
00093   memcpy (cuts->cut[cuts->sz], cut, sizeof (unsigned int) * c_sz);
00094   cuts->sz++;
00095   return 0;
00096 }
00097 
00098 /* ========================================================================= */
00099 /** @brief parse input */
00100 static inline int mc_parseargs (int argc,
00101                                 char **argv)
00102 {
00103   int c;
00104   while ((c = getopt (argc, argv, "f:l:")) != EOF)
00105   {
00106     switch (c)
00107     {
00108     case 'f':
00109       file_name = optarg;
00110       break;
00111     case 'l':
00112       lvl = atoi (optarg);
00113       break;
00114     default:
00115       mc_usage (argv);
00116       return 1;
00117     }
00118   }
00119   /* test that we have an input file */
00120   if (!file_name)
00121   {
00122     mc_usage (argv);
00123     return 1;
00124   }
00125   /* report options */
00126   fprintf (stderr, "reading graph from %s\nusing shrinking level %u\n",
00127            file_name, lvl);
00128   return 0;
00129 }
00130 
00131 /* ========================================================================= */
00132 /** @brief example of usage of the Min Cut algorithm as implemented in
00133  * (EGalgMinCut).
00134  * 
00135  * We read a file from the input whose two first numbers are the number of nodes
00136  * and edges (we assume that the graph is undirected ), and then a 3-tupla with
00137  * head tail capacity. we use the last field (capacity) as the capacity of the
00138  * algorithm, and compute the minimum global cut. */
00139 int main (int argc,
00140           char **argv)
00141 {
00142   int rval = 0,
00143     n_read;
00144   FILE *in_file = 0;
00145   unsigned int register i;
00146   unsigned int head,
00147     tail;
00148   EGlpNum_t cap;
00149   EGtimer_t cut_timer;
00150   EGalgMCgraph_t G;
00151   char l_str[1024];
00152   EGalgMCcbk_t cb;
00153   mc_all_cuts_t all_cuts;
00154   all_cuts.max_sz = all_cuts.sz = 0;
00155   EGtimerReset (&cut_timer);
00156   EGlpNumStart ();
00157   EGalgMCcbkInit (&cb);
00158   cb.do_fn = mc_store_cuts;
00159   EGlpNumSet (cb.cutoff, 2.0);
00160   cb.param = &all_cuts;
00161   EGalgMCgraphInit (&G);
00162   EGlpNumInitVar (cap);
00163   /* test we have an input file */
00164   rval = mc_parseargs (argc, argv);
00165   CHECKRVALG (rval, CLEANUP);
00166   in_file = fopen (file_name, "r");
00167   if (!in_file)
00168   {
00169     fprintf (stderr, "Can't open file %s\n", argv[1]);
00170     mc_usage (argv);
00171     rval = 1;
00172     goto CLEANUP;
00173   }
00174   /* now we start reading the file */
00175   n_read = fscanf (in_file, "%u %u", &G.G.n_onodes, &G.G.n_oedges);
00176   TESTG ((rval = (n_read != 2)), CLEANUP, "Can't read n_nodes and n_endges "
00177          "from file");
00178   if (!G.G.n_oedges || !G.G.n_onodes)
00179   {
00180     fprintf (stderr, "Problem is trivial with %u nodes and %u edges\n",
00181              G.G.n_onodes, G.G.n_oedges);
00182     G.G.n_onodes = G.G.n_oedges = 0;
00183     goto CLEANUP;
00184   }
00185   fprintf (stderr, "Reading graph on %u nodes and %u edges...", G.G.n_onodes,
00186            G.G.n_oedges);
00187   G.all_nodes = EGsMalloc (EGalgMCnode_t, G.G.n_onodes);
00188   G.all_edges = EGsMalloc (EGalgMCedge_t, G.G.n_oedges);
00189   for (i = G.G.n_onodes; i--;)
00190   {
00191     EGalgMCnodeInit (G.all_nodes + i);
00192     EGeListAddAfter (&(G.all_nodes[i].lvl_cn), G.lvl_list);
00193     G.all_nodes[i].id = i;
00194     EGsrkAddNode (&(G.G), &(G.all_nodes[i].node));
00195   }
00196   for (i = G.G.n_oedges; i--;)
00197   {
00198     EGalgMCedgeInit (G.all_edges + i);
00199     G.all_edges[i].id = i;
00200     n_read = fscanf (in_file, "%u %u %s", &head, &tail, l_str);
00201     TESTG ((rval = (n_read != 3)), CLEANUP, "Can't read head tail capacity");
00202     EGlpNumReadStr (cap, l_str);
00203     EGlpNumCopy (G.all_edges[i].edge.weight, cap);
00204     EGsrkAddEdge (&(G.G), &(G.all_nodes[head].node), &(G.all_nodes[tail].node),
00205                   &(G.all_edges[i].edge));
00206   }
00207   EGlpNumCopySum (G.cut_val, G.all_nodes[0].node.weight, oneLpNum);
00208   EGlpNumCopy (G.epsilon, epsLpNum);
00209   G.cut = EGsMalloc (unsigned int,
00210                      G.G.n_onodes);
00211   fclose (in_file);
00212   in_file = 0;
00213 
00214   /* now we call the min cut algorithm */
00215   fprintf (stderr, "...done\nComputing Min Cut...");
00216   EGtimerStart (&cut_timer);
00217   rval = EGalgMC (&G, &cb, lvl);
00218   EGtimerStop (&cut_timer);
00219   fprintf (stderr, "...done in %lf seconds\n\tValue: %lf\n", cut_timer.time,
00220            EGlpNumToLf (G.cut_val));
00221 
00222   /* now we display all cuts */
00223 #if 0
00224   fprintf (stderr, "Number of cuts found: %u\n", all_cuts.sz);
00225   for (i = all_cuts.sz; i--;)
00226   {
00227     fprintf (stderr, "cut %u: val %lf, sz %u, elems ", i,
00228              EGlpNumToLf (all_cuts.cut_val[i]), all_cuts.cut_sz[i]);
00229     for (j = all_cuts.cut_sz[i]; j--;)
00230       fprintf (stderr, " %u", all_cuts.cut[i][j]);
00231     fprintf (stderr, "\n");
00232   }
00233 #endif
00234 
00235   /* ending */
00236 CLEANUP:
00237   if (in_file)
00238     fclose (in_file);
00239   EGlpNumClearVar (cap);
00240   if (all_cuts.sz)
00241   {
00242     for (i = all_cuts.sz; i--;)
00243     {
00244       EGlpNumClearVar (all_cuts.cut_val[i]);
00245       EGfree (all_cuts.cut[i]);
00246     }
00247     EGfree (all_cuts.cut);
00248     EGfree (all_cuts.cut_val);
00249     EGfree (all_cuts.cut_sz);
00250   }
00251   if (G.G.n_onodes)
00252   {
00253     for (i = G.G.n_onodes; i--;)
00254       EGalgMCnodeClear (G.all_nodes + i);
00255     EGfree (G.all_nodes);
00256   }
00257   if (G.G.n_oedges)
00258   {
00259     for (i = G.G.n_oedges; i--;)
00260       EGalgMCedgeClear (G.all_edges + i);
00261     EGfree (G.all_edges);
00262   }
00263   EGalgMCprofile;
00264   EGalgPRprofile;
00265   if (G.cut)
00266     EGfree (G.cut);
00267   EGalgMCgraphClear (&G);
00268   EGlpNumExit ();
00269   return rval;
00270 }
00271 
00272 /* ========================================================================= */
00273 /** @} */

Generated on Mon Jan 30 08:48:52 2006 for EGlib by  doxygen 1.4.5