tools/lgf-gen.cc
author alpar
Tue, 05 Jun 2007 10:59:16 +0000
changeset 2446 dd20d76eed13
parent 2410 fe46b61da4e3
child 2447 260ce674cc65
permissions -rw-r--r--
A minimum spanning tree based TSP algorithm is added (-tsp2)
     1 /* -*- C++ -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library
     4  *
     5  * Copyright (C) 2003-2007
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     9  * Permission to use, modify and distribute this software is granted
    10  * provided that this copyright notice appears in all copies. For
    11  * precise terms see the accompanying LICENSE file.
    12  *
    13  * This software is provided "AS IS" with no warranty of any kind,
    14  * express or implied, and with no claim as to its suitability for any
    15  * purpose.
    16  *
    17  */
    18 
    19 #include <lemon/list_graph.h>
    20 #include <lemon/graph_utils.h>
    21 #include <lemon/random.h>
    22 #include <lemon/dim2.h>
    23 #include <lemon/bfs.h>
    24 #include <lemon/counter.h>
    25 #include <lemon/suurballe.h>
    26 #include <lemon/graph_to_eps.h>
    27 #include <lemon/graph_writer.h>
    28 #include <lemon/arg_parser.h>
    29 #include <lemon/euler.h>
    30 #include <cmath>
    31 #include <algorithm>
    32 #include <lemon/unionfind.h>
    33 #include <lemon/time_measure.h>
    34 
    35 using namespace lemon;
    36 
    37 typedef dim2::Point<double> Point;
    38 
    39 UGRAPH_TYPEDEFS(ListUGraph);
    40 
    41 bool progress=true;
    42 
    43 int N;
    44 // int girth;
    45 
    46 ListUGraph g;
    47 
    48 std::vector<Node> nodes;
    49 ListUGraph::NodeMap<Point> coords(g);
    50 
    51 
    52 double totalLen(){
    53   double tlen=0;
    54   for(UEdgeIt e(g);e!=INVALID;++e)
    55     tlen+=sqrt((coords[g.source(e)]-coords[g.target(e)]).normSquare());
    56   return tlen;
    57 }
    58 
    59 int tsp_impr_num=0;
    60 
    61 const double EPSILON=1e-8; 
    62 bool tsp_improve(Node u, Node v)
    63 {
    64   double luv=std::sqrt((coords[v]-coords[u]).normSquare());
    65   Node u2=u;
    66   Node v2=v;
    67   do {
    68     Node n;
    69     for(IncEdgeIt e(g,v2);(n=g.runningNode(e))==u2;++e);
    70     u2=v2;
    71     v2=n;
    72     if(luv+std::sqrt((coords[v2]-coords[u2]).normSquare())-EPSILON>
    73        std::sqrt((coords[u]-coords[u2]).normSquare())+
    74        std::sqrt((coords[v]-coords[v2]).normSquare()))
    75       {
    76  	g.erase(findUEdge(g,u,v));
    77  	g.erase(findUEdge(g,u2,v2));
    78 	g.addEdge(u2,u);
    79 	g.addEdge(v,v2);
    80 	tsp_impr_num++;
    81 	return true;
    82       }
    83   } while(v2!=u);
    84   return false;
    85 }
    86 
    87 bool tsp_improve(Node u)
    88 {
    89   for(IncEdgeIt e(g,u);e!=INVALID;++e)
    90     if(tsp_improve(u,g.runningNode(e))) return true;
    91   return false;
    92 }
    93 
    94 void tsp_improve()
    95 {
    96   bool b;
    97   do {
    98     b=false;
    99     for(NodeIt n(g);n!=INVALID;++n)
   100       if(tsp_improve(n)) b=true;
   101   } while(b);
   102 }
   103 
   104 void tsp()
   105 {
   106   for(int i=0;i<N;i++) g.addEdge(nodes[i],nodes[(i+1)%N]);
   107   tsp_improve();
   108 }
   109 
   110 class Line
   111 {
   112 public:
   113   Point a;
   114   Point b;
   115   Line(Point _a,Point _b) :a(_a),b(_b) {}
   116   Line(Node _a,Node _b) : a(coords[_a]),b(coords[_b]) {}
   117   Line(const Edge &e) : a(coords[g.source(e)]),b(coords[g.target(e)]) {}
   118   Line(const UEdge &e) : a(coords[g.source(e)]),b(coords[g.target(e)]) {}
   119 };
   120   
   121 inline std::ostream& operator<<(std::ostream &os, const Line &l)
   122 {
   123   os << l.a << "->" << l.b;
   124   return os;
   125 }
   126 
   127 bool cross(Line a, Line b) 
   128 {
   129   Point ao=rot90(a.b-a.a);
   130   Point bo=rot90(b.b-b.a);
   131   return (ao*(b.a-a.a))*(ao*(b.b-a.a))<0 &&
   132     (bo*(a.a-b.a))*(bo*(a.b-b.a))<0;
   133 }
   134 
   135 struct Pedge
   136 {
   137   Node a;
   138   Node b;
   139   double len;
   140 };
   141 
   142 bool pedgeLess(Pedge a,Pedge b)
   143 {
   144   return a.len<b.len;
   145 }
   146 
   147 std::vector<UEdge> edges;
   148 
   149 void triangle()
   150 {
   151   Counter cnt("Number of edges added: ");
   152   std::vector<Pedge> pedges;
   153   for(NodeIt n(g);n!=INVALID;++n) 
   154     for(NodeIt m=++(NodeIt(n));m!=INVALID;++m)
   155       {
   156 	Pedge p;
   157 	p.a=n;
   158 	p.b=m;
   159 	p.len=(coords[m]-coords[n]).normSquare();
   160 	pedges.push_back(p);
   161       }
   162   std::sort(pedges.begin(),pedges.end(),pedgeLess);
   163   for(std::vector<Pedge>::iterator pi=pedges.begin();pi!=pedges.end();++pi)
   164     {
   165       Line li(pi->a,pi->b);
   166       UEdgeIt e(g);
   167       for(;e!=INVALID && !cross(e,li);++e) ;
   168       UEdge ne;
   169       if(e==INVALID) {
   170 	ne=g.addEdge(pi->a,pi->b);
   171 	edges.push_back(ne);
   172 	cnt++;
   173       }
   174     }
   175 }
   176 
   177 void sparse(int d) 
   178 {
   179   Counter cnt("Number of edges removed: ");
   180   Bfs<ListUGraph> bfs(g);
   181   for(std::vector<UEdge>::reverse_iterator ei=edges.rbegin();
   182       ei!=edges.rend();++ei)
   183     {
   184       Node a=g.source(*ei);
   185       Node b=g.target(*ei);
   186       g.erase(*ei);
   187       bfs.run(a,b);
   188       if(bfs.predEdge(b)==INVALID || bfs.dist(b)>d)
   189 	g.addEdge(a,b);
   190       else cnt++;
   191     }
   192 }
   193 
   194 void sparse2(int d) 
   195 {
   196   Counter cnt("Number of edges removed: ");
   197   for(std::vector<UEdge>::reverse_iterator ei=edges.rbegin();
   198       ei!=edges.rend();++ei)
   199     {
   200       Node a=g.source(*ei);
   201       Node b=g.target(*ei);
   202       g.erase(*ei);
   203       ConstMap<Edge,int> cegy(1);
   204       Suurballe<ListUGraph,ConstMap<Edge,int> > sur(g,cegy,a,b);
   205       int k=sur.run(2);
   206       if(k<2 || sur.totalLength()>d)
   207 	g.addEdge(a,b);
   208       else cnt++;
   209 //       else std::cout << "Remove edge " << g.id(a) << "-" << g.id(b) << '\n';
   210     }
   211 }
   212 
   213 void sparseTriangle(int d)
   214 {
   215   Counter cnt("Number of edges added: ");
   216   std::vector<Pedge> pedges;
   217   for(NodeIt n(g);n!=INVALID;++n) 
   218     for(NodeIt m=++(NodeIt(n));m!=INVALID;++m)
   219       {
   220 	Pedge p;
   221 	p.a=n;
   222 	p.b=m;
   223 	p.len=(coords[m]-coords[n]).normSquare();
   224 	pedges.push_back(p);
   225       }
   226   std::sort(pedges.begin(),pedges.end(),pedgeLess);
   227   for(std::vector<Pedge>::iterator pi=pedges.begin();pi!=pedges.end();++pi)
   228     {
   229       Line li(pi->a,pi->b);
   230       UEdgeIt e(g);
   231       for(;e!=INVALID && !cross(e,li);++e) ;
   232       UEdge ne;
   233       if(e==INVALID) {
   234 	ConstMap<Edge,int> cegy(1);
   235 	Suurballe<ListUGraph,ConstMap<Edge,int> >
   236 	  sur(g,cegy,pi->a,pi->b);
   237 	int k=sur.run(2);
   238 	if(k<2 || sur.totalLength()>d)
   239 	  {
   240 	    ne=g.addEdge(pi->a,pi->b);
   241 	    edges.push_back(ne);
   242 	    cnt++;
   243 	  }
   244       }
   245     }
   246 }
   247 
   248 void minTree() {
   249   int en=0;
   250   int pr=0;
   251   std::vector<Pedge> pedges;
   252   Timer T;
   253   std::cout << T.realTime() << "s: Setting up the edges...\n";
   254   for(NodeIt n(g);n!=INVALID;++n) 
   255     {
   256       for(NodeIt m=++(NodeIt(n));m!=INVALID;++m)
   257 	{
   258 	  Pedge p;
   259 	  p.a=n;
   260 	  p.b=m;
   261 	  p.len=(coords[m]-coords[n]).normSquare();
   262 	  pedges.push_back(p);
   263 	}
   264       if(progress && en>=pr*double(N)/100) 
   265 	{
   266 	  std::cout << pr << "%  \r" << std::flush;
   267 	  pr++;
   268 	}
   269     }
   270   std::cout << T.realTime() << "s: Sorting the edges...\n";
   271   std::sort(pedges.begin(),pedges.end(),pedgeLess);
   272   std::cout << T.realTime() << "s: Creating the tree...\n";
   273   ListUGraph::NodeMap<int> comp(g);
   274   UnionFind<ListUGraph::NodeMap<int> > uf(comp);
   275   for (NodeIt it(g); it != INVALID; ++it)
   276     uf.insert(it);  
   277   for(std::vector<Pedge>::iterator pi=pedges.begin();pi!=pedges.end();++pi)
   278     {
   279       if ( uf.join(pi->a,pi->b) ) {
   280 	g.addEdge(pi->a,pi->b);
   281 	en++;
   282 	if(en>=N-1)
   283 	  break;
   284       }
   285     }
   286   std::cout << T.realTime() << "s: Done\n";
   287 }
   288 
   289 Node common(UEdge e, UEdge f)
   290 {
   291   return (g.source(e)==g.source(f)||g.source(e)==g.target(f))?
   292 	g.source(e):g.target(e);
   293 }
   294 
   295 void tsp2() 
   296 {
   297   std::cout << "Find a tree..." << std::endl;
   298 
   299   minTree();
   300 
   301   std::cout << "Total edge length (tree) : " << totalLen() << std::endl;
   302 
   303   std::cout << "Make it Euler..." << std::endl;
   304 
   305   {
   306     std::vector<Node> leafs;
   307     for(NodeIt n(g);n!=INVALID;++n)
   308       if(countIncEdges(g,n)%2==1) leafs.push_back(n);
   309     for(unsigned int i=0;i<leafs.size();i+=2)
   310       g.addEdge(leafs[i],leafs[i+1]);
   311   }
   312 
   313   for(NodeIt n(g);n!=INVALID;++n)
   314     if(countIncEdges(g,n)%2)
   315       std::cout << "GEBASZ!!!" << std::endl;
   316   
   317   std::cout << "Number of edges : " << countUEdges(g) << std::endl;
   318 
   319 //   for(NodeIt n(g);n!=INVALID;++n)
   320 //     if(countIncEdges(g,n)>2)
   321 //       std::cout << "+";
   322 //   std::cout << std::endl;
   323   
   324   std::cout << "Total edge length (euler) : " << totalLen() << std::endl;
   325 
   326   ListUGraph::UEdgeMap<UEdge> enext(g);
   327   {
   328     UEulerIt<ListUGraph> e(g);
   329     UEdge eo=e;
   330     UEdge ef=e;
   331 //     std::cout << "Tour edge: " << g.id(UEdge(e)) << std::endl;      
   332     for(++e;e!=INVALID;++e)
   333       {
   334 // 	std::cout << "Tour edge: " << g.id(UEdge(e)) << std::endl;      
   335 	enext[eo]=e;
   336 	eo=e;
   337       }
   338     enext[eo]=ef;
   339   }
   340   
   341   std::cout << "Creating a tour from that..." << std::endl;
   342   
   343   int nnum = countNodes(g);
   344   int ednum = countUEdges(g);
   345   
   346   for(UEdge p=UEdgeIt(g);ednum>nnum;p=enext[p]) 
   347     {
   348 //       std::cout << "Checking edge " << g.id(p) << std::endl;      
   349       UEdge e=enext[p];
   350       UEdge f=enext[e];
   351       Node n2=common(e,f);
   352       Node n1=g.oppositeNode(n2,e);
   353       Node n3=g.oppositeNode(n2,f);
   354       if(countIncEdges(g,n2)>2)
   355 	{
   356 // 	  std::cout << "Remove an Edge" << std::endl;
   357 	  UEdge ff=enext[f];
   358 	  g.erase(e);
   359 	  g.erase(f);
   360 	  UEdge ne=g.addEdge(n1,n3);
   361 	  enext[p]=ne;
   362 	  enext[ne]=ff;
   363 	  ednum--;
   364 	}
   365     }
   366 
   367   std::cout << "Total edge length (tour) : " << totalLen() << std::endl;
   368 
   369   tsp_improve();
   370   
   371   std::cout << "Total edge length (2-opt tour) : " << totalLen() << std::endl;
   372 }
   373 
   374 
   375 int main(int argc,const char **argv) 
   376 {
   377   ArgParser ap(argc,argv);
   378 
   379 //   bool eps;
   380   bool disc_d, square_d, gauss_d;
   381 //   bool tsp_a,two_a,tree_a;
   382   int num_of_cities=1;
   383   double area=1;
   384   N=100;
   385 //   girth=10;
   386   std::string ndist("disc");
   387   ap.refOption("n", "Number of nodes (default is 100)", N)
   388     .intOption("g", "Girth parameter (default is 10)", 10)
   389     .refOption("cities", "Number of cities (default is 1)", num_of_cities)
   390     .refOption("area", "Full relative area of the cities (default is 1)", area)
   391     .refOption("disc", "Nodes are evenly distributed on a unit disc (default)",disc_d)
   392     .optionGroup("dist", "disc")
   393     .refOption("square", "Nodes are evenly distributed on a unit square", square_d)
   394     .optionGroup("dist", "square")
   395     .refOption("gauss",
   396 	    "Nodes are located according to a two-dim gauss distribution",
   397 	    gauss_d)
   398     .optionGroup("dist", "gauss")
   399 //     .mandatoryGroup("dist")
   400     .onlyOneGroup("dist")
   401     .boolOption("eps", "Also generate .eps output (prefix.eps)")
   402     .boolOption("dir", "Directed graph is generated (each edges are replaced by two directed ones)")
   403     .boolOption("2con", "Create a two connected planar graph")
   404     .optionGroup("alg","2con")
   405     .boolOption("tree", "Create a min. cost spanning tree")
   406     .optionGroup("alg","tree")
   407     .boolOption("tsp", "Create a TSP tour")
   408     .optionGroup("alg","tsp")
   409     .boolOption("tsp2", "Create a TSP tour (tree based)")
   410     .optionGroup("alg","tsp2")
   411     .onlyOneGroup("alg")
   412     .other("[prefix]","Prefix of the output files. Default is 'lgf-gen-out'")
   413     .run();
   414   
   415   std::string prefix;
   416   switch(ap.files().size()) 
   417     {
   418     case 0:
   419       prefix="lgf-gen-out";
   420       break;
   421     case 1:
   422       prefix=ap.files()[0];
   423       break;
   424     default:
   425       std::cerr << "\nAt most one prefix can be given\n\n";
   426       exit(1);
   427     }
   428   
   429   double sum_sizes=0;
   430   std::vector<double> sizes;
   431   std::vector<double> cum_sizes;
   432   for(int s=0;s<num_of_cities;s++) 
   433     {
   434       // 	sum_sizes+=rnd.exponential();
   435       double d=rnd();
   436       sum_sizes+=d;
   437       sizes.push_back(d);
   438       cum_sizes.push_back(sum_sizes);
   439     }
   440   int i=0;
   441   for(int s=0;s<num_of_cities;s++) 
   442     {
   443       Point center=(num_of_cities==1?Point(0,0):rnd.disc());
   444       if(gauss_d)
   445 	for(;i<N*(cum_sizes[s]/sum_sizes);i++) {
   446 	  Node n=g.addNode();
   447 	  nodes.push_back(n);
   448 	  coords[n]=center+rnd.gauss2()*area*
   449 	    std::sqrt(sizes[s]/sum_sizes);
   450 	}
   451       else if(square_d)
   452 	for(;i<N*(cum_sizes[s]/sum_sizes);i++) {
   453 	  Node n=g.addNode();
   454 	  nodes.push_back(n);
   455 	  coords[n]=center+Point(rnd()*2-1,rnd()*2-1)*area*
   456 	    std::sqrt(sizes[s]/sum_sizes);
   457 	}
   458       else if(disc_d || true)
   459 	for(;i<N*(cum_sizes[s]/sum_sizes);i++) {
   460 	  Node n=g.addNode();
   461 	  nodes.push_back(n);
   462 	  coords[n]=center+rnd.disc()*area*
   463 	    std::sqrt(sizes[s]/sum_sizes);
   464 	}
   465     }
   466   
   467   if(ap["tsp"]) {
   468     tsp();
   469     std::cout << "#2-opt improvements: " << tsp_impr_num << std::endl;
   470   }
   471   if(ap["tsp2"]) {
   472     tsp2();
   473     std::cout << "#2-opt improvements: " << tsp_impr_num << std::endl;
   474   }
   475   else if(ap["2con"]) {
   476     std::cout << "Make triangles\n";
   477     //   triangle();
   478     sparseTriangle(ap["g"]);
   479     std::cout << "Make it sparser\n";
   480     sparse2(ap["g"]);
   481   }
   482   else if(ap["tree"]) {
   483     minTree();
   484   }
   485   
   486 
   487   std::cout << "Number of nodes    : " << countNodes(g) << std::endl;
   488   std::cout << "Number of edges    : " << countUEdges(g) << std::endl;
   489   double tlen=0;
   490   for(UEdgeIt e(g);e!=INVALID;++e)
   491     tlen+=sqrt((coords[g.source(e)]-coords[g.target(e)]).normSquare());
   492   std::cout << "Total edge length  : " << tlen << std::endl;
   493   if(ap["eps"])
   494     graphToEps(g,prefix+".eps").
   495       scale(600).nodeScale(.2).edgeWidthScale(.001).preScale(false).
   496       coords(coords).run();
   497 
   498   if(ap["dir"])
   499     GraphWriter<ListUGraph>(prefix+".lgf",g).
   500       writeNodeMap("coordinates_x",scaleMap(xMap(coords),600)).
   501       writeNodeMap("coordinates_y",scaleMap(yMap(coords),600)).
   502       run();
   503   else UGraphWriter<ListUGraph>(prefix+".lgf",g).
   504 	 writeNodeMap("coordinates_x",scaleMap(xMap(coords),600)).
   505 	 writeNodeMap("coordinates_y",scaleMap(yMap(coords),600)).
   506 	 run();
   507 }
   508