tools/lgf-gen.cc
author deba
Wed, 07 Mar 2007 11:56:14 +0000
changeset 2396 658c04d74729
parent 2390 8450951a8e2d
child 2402 da8eb8f4ea41
permissions -rw-r--r--
naming convention:
header sentry
     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 <cmath>
    30 #include <algorithm>
    31 #include <lemon/unionfind.h>
    32 
    33 using namespace lemon;
    34 
    35 typedef dim2::Point<double> Point;
    36 
    37 UGRAPH_TYPEDEFS(ListUGraph);
    38 
    39 int N;
    40 int girth;
    41 
    42 ListUGraph g;
    43 
    44 std::vector<Node> nodes;
    45 ListUGraph::NodeMap<Point> coords(g);
    46 
    47 int tsp_impr_num=0;
    48 
    49 const double EPSILON=1e-8; 
    50 bool tsp_improve(Node u, Node v)
    51 {
    52   double luv=std::sqrt((coords[v]-coords[u]).normSquare());
    53   Node u2=u;
    54   Node v2=v;
    55   do {
    56     Node n;
    57     for(IncEdgeIt e(g,v2);(n=g.runningNode(e))==u2;++e);
    58     u2=v2;
    59     v2=n;
    60     if(luv+std::sqrt((coords[v2]-coords[u2]).normSquare())-EPSILON>
    61        std::sqrt((coords[u]-coords[u2]).normSquare())+
    62        std::sqrt((coords[v]-coords[v2]).normSquare()))
    63       {
    64  	g.erase(findUEdge(g,u,v));
    65  	g.erase(findUEdge(g,u2,v2));
    66 	g.addEdge(u2,u);
    67 	g.addEdge(v,v2);
    68 	tsp_impr_num++;
    69 	return true;
    70       }
    71   } while(v2!=u);
    72   return false;
    73 }
    74 
    75 bool tsp_improve(Node u)
    76 {
    77   for(IncEdgeIt e(g,u);e!=INVALID;++e)
    78     if(tsp_improve(u,g.runningNode(e))) return true;
    79   return false;
    80 }
    81 
    82 void tsp_improve()
    83 {
    84   bool b;
    85   do {
    86     b=false;
    87     for(NodeIt n(g);n!=INVALID;++n)
    88       if(tsp_improve(n)) b=true;
    89   } while(b);
    90 }
    91 
    92 void tsp()
    93 {
    94   for(int i=0;i<N;i++) g.addEdge(nodes[i],nodes[(i+1)%N]);
    95   tsp_improve();
    96 }
    97 
    98 class Line
    99 {
   100 public:
   101   Point a;
   102   Point b;
   103   Line(Point _a,Point _b) :a(_a),b(_b) {}
   104   Line(Node _a,Node _b) : a(coords[_a]),b(coords[_b]) {}
   105   Line(const Edge &e) : a(coords[g.source(e)]),b(coords[g.target(e)]) {}
   106   Line(const UEdge &e) : a(coords[g.source(e)]),b(coords[g.target(e)]) {}
   107 };
   108   
   109 inline std::ostream& operator<<(std::ostream &os, const Line &l)
   110 {
   111   os << l.a << "->" << l.b;
   112   return os;
   113 }
   114 
   115 bool cross(Line a, Line b) 
   116 {
   117   Point ao=rot90(a.b-a.a);
   118   Point bo=rot90(b.b-b.a);
   119   return (ao*(b.a-a.a))*(ao*(b.b-a.a))<0 &&
   120     (bo*(a.a-b.a))*(bo*(a.b-b.a))<0;
   121 }
   122 
   123 struct Pedge
   124 {
   125   Node a;
   126   Node b;
   127   double len;
   128 };
   129 
   130 bool pedgeLess(Pedge a,Pedge b)
   131 {
   132   return a.len<b.len;
   133 }
   134 
   135 std::vector<UEdge> edges;
   136 
   137 void triangle()
   138 {
   139   Counter cnt("Number of edges added: ");
   140   std::vector<Pedge> pedges;
   141   for(NodeIt n(g);n!=INVALID;++n) 
   142     for(NodeIt m=++(NodeIt(n));m!=INVALID;++m)
   143       {
   144 	Pedge p;
   145 	p.a=n;
   146 	p.b=m;
   147 	p.len=(coords[m]-coords[n]).normSquare();
   148 	pedges.push_back(p);
   149       }
   150   std::sort(pedges.begin(),pedges.end(),pedgeLess);
   151   for(std::vector<Pedge>::iterator pi=pedges.begin();pi!=pedges.end();++pi)
   152     {
   153       Line li(pi->a,pi->b);
   154       UEdgeIt e(g);
   155       for(;e!=INVALID && !cross(e,li);++e) ;
   156       UEdge ne;
   157       if(e==INVALID) {
   158 	ne=g.addEdge(pi->a,pi->b);
   159 	edges.push_back(ne);
   160 	cnt++;
   161       }
   162     }
   163 }
   164 
   165 void sparse(int d) 
   166 {
   167   Counter cnt("Number of edges removed: ");
   168   Bfs<ListUGraph> bfs(g);
   169   for(std::vector<UEdge>::reverse_iterator ei=edges.rbegin();
   170       ei!=edges.rend();++ei)
   171     {
   172       Node a=g.source(*ei);
   173       Node b=g.target(*ei);
   174       g.erase(*ei);
   175       bfs.run(a,b);
   176       if(bfs.predEdge(b)==INVALID || bfs.dist(b)>d)
   177 	g.addEdge(a,b);
   178       else cnt++;
   179     }
   180 }
   181 
   182 void sparse2(int d) 
   183 {
   184   Counter cnt("Number of edges removed: ");
   185   for(std::vector<UEdge>::reverse_iterator ei=edges.rbegin();
   186       ei!=edges.rend();++ei)
   187     {
   188       Node a=g.source(*ei);
   189       Node b=g.target(*ei);
   190       g.erase(*ei);
   191       ConstMap<Edge,int> cegy(1);
   192       Suurballe<ListUGraph,ConstMap<Edge,int> > sur(g,cegy,a,b);
   193       int k=sur.run(2);
   194       if(k<2 || sur.totalLength()>d)
   195 	g.addEdge(a,b);
   196       else cnt++;
   197 //       else std::cout << "Remove edge " << g.id(a) << "-" << g.id(b) << '\n';
   198     }
   199 }
   200 
   201 void sparseTriangle(int d)
   202 {
   203   Counter cnt("Number of edges added: ");
   204   std::vector<Pedge> pedges;
   205   for(NodeIt n(g);n!=INVALID;++n) 
   206     for(NodeIt m=++(NodeIt(n));m!=INVALID;++m)
   207       {
   208 	Pedge p;
   209 	p.a=n;
   210 	p.b=m;
   211 	p.len=(coords[m]-coords[n]).normSquare();
   212 	pedges.push_back(p);
   213       }
   214   std::sort(pedges.begin(),pedges.end(),pedgeLess);
   215   for(std::vector<Pedge>::iterator pi=pedges.begin();pi!=pedges.end();++pi)
   216     {
   217       Line li(pi->a,pi->b);
   218       UEdgeIt e(g);
   219       for(;e!=INVALID && !cross(e,li);++e) ;
   220       UEdge ne;
   221       if(e==INVALID) {
   222 	ConstMap<Edge,int> cegy(1);
   223 	Suurballe<ListUGraph,ConstMap<Edge,int> >
   224 	  sur(g,cegy,pi->a,pi->b);
   225 	int k=sur.run(2);
   226 	if(k<2 || sur.totalLength()>d)
   227 	  {
   228 	    ne=g.addEdge(pi->a,pi->b);
   229 	    edges.push_back(ne);
   230 	    cnt++;
   231 	  }
   232       }
   233     }
   234 }
   235 
   236 void minTree() {
   237   std::vector<Pedge> pedges;
   238   for(NodeIt n(g);n!=INVALID;++n) 
   239     for(NodeIt m=++(NodeIt(n));m!=INVALID;++m)
   240       {
   241 	Pedge p;
   242 	p.a=n;
   243 	p.b=m;
   244 	p.len=(coords[m]-coords[n]).normSquare();
   245 	pedges.push_back(p);
   246       }
   247   std::sort(pedges.begin(),pedges.end(),pedgeLess);
   248   ListUGraph::NodeMap<int> comp(g);
   249   UnionFind<ListUGraph::NodeMap<int> > uf(comp);
   250   for (NodeIt it(g); it != INVALID; ++it)
   251     uf.insert(it);
   252 
   253   int en=0;
   254   for(std::vector<Pedge>::iterator pi=pedges.begin();pi!=pedges.end();++pi)
   255     {
   256       if ( uf.join(pi->a,pi->b) ) {
   257 	g.addEdge(pi->a,pi->b);
   258 	en++;
   259 	if(en>=N-1) return;
   260       }
   261     }
   262 }
   263 
   264 
   265 
   266 int main(int argc,char **argv) 
   267 {
   268   ArgParser ap(argc,argv);
   269 
   270   bool eps;
   271   bool disc_d, square_d, gauss_d;
   272   bool tsp_a,two_a,tree_a;
   273   int num_of_cities=1;
   274   double area=1;
   275   N=100;
   276   girth=10;
   277   std::string ndist("disc");
   278   ap.option("n", "Number of nodes (default is 100)", N)
   279     .option("g", "Girth parameter (default is 10)", girth)
   280     .option("cities", "Number of cities (default is 1)", num_of_cities)
   281     .option("area", "Full relative area of the cities (default is 1)", area)
   282     .option("disc", "Nodes are evenly distributed on a unit disc (default)",disc_d)
   283     .optionGroup("dist", "disc")
   284     .option("square", "Nodes are evenly distributed on a unit square", square_d)
   285     .optionGroup("dist", "square")
   286     .option("gauss",
   287 	    "Nodes are located according to a two-dim gauss distribution",
   288 	    gauss_d)
   289     .optionGroup("dist", "gauss")
   290 //     .mandatoryGroup("dist")
   291     .onlyOneGroup("dist")
   292     .option("eps", "Also generate .eps output (prefix.eps)",eps)
   293     .option("2con", "Create a two connected planar graph",two_a)
   294     .optionGroup("alg","2con")
   295     .option("tree", "Create a min. cost spanning tree",tree_a)
   296     .optionGroup("alg","tree")
   297     .option("tsp", "Create a TSP tour",tsp_a)
   298     .optionGroup("alg","tsp")
   299     .onlyOneGroup("alg")
   300     .other("[prefix]","Prefix of the output files. Default is 'lgf-gen-out'")
   301     .run();
   302   
   303   std::string prefix;
   304   switch(ap.files().size()) 
   305     {
   306     case 0:
   307       prefix="lgf-gen-out";
   308       break;
   309     case 1:
   310       prefix=ap.files()[0];
   311       break;
   312     default:
   313       std::cerr << "\nAt most one prefix can be given\n\n";
   314       exit(1);
   315     }
   316   
   317   double sum_sizes=0;
   318   std::vector<double> sizes;
   319   std::vector<double> cum_sizes;
   320   for(int s=0;s<num_of_cities;s++) 
   321     {
   322       // 	sum_sizes+=rnd.exponential();
   323       double d=rnd();
   324       sum_sizes+=d;
   325       sizes.push_back(d);
   326       cum_sizes.push_back(sum_sizes);
   327     }
   328   int i=0;
   329   for(int s=0;s<num_of_cities;s++) 
   330     {
   331       Point center=(num_of_cities==1?Point(0,0):rnd.disc());
   332       if(gauss_d)
   333 	for(;i<N*(cum_sizes[s]/sum_sizes);i++) {
   334 	  Node n=g.addNode();
   335 	  nodes.push_back(n);
   336 	  coords[n]=center+rnd.gauss2()*area*
   337 	    std::sqrt(sizes[s]/sum_sizes);
   338 	}
   339       else if(square_d)
   340 	for(;i<N*(cum_sizes[s]/sum_sizes);i++) {
   341 	  Node n=g.addNode();
   342 	  nodes.push_back(n);
   343 	  coords[n]=center+Point(rnd()*2-1,rnd()*2-1)*area*
   344 	    std::sqrt(sizes[s]/sum_sizes);
   345 	}
   346       else if(disc_d || true)
   347 	for(;i<N*(cum_sizes[s]/sum_sizes);i++) {
   348 	  Node n=g.addNode();
   349 	  nodes.push_back(n);
   350 	  coords[n]=center+rnd.disc()*area*
   351 	    std::sqrt(sizes[s]/sum_sizes);
   352 	}
   353     }
   354   
   355   if(tsp_a) {
   356     tsp();
   357     std::cout << "#2-opt improvements: " << tsp_impr_num << std::endl;
   358   }
   359   else if(two_a) {
   360     std::cout << "Make triangles\n";
   361     //   triangle();
   362     sparseTriangle(girth);
   363     std::cout << "Make it sparser\n";
   364     sparse2(girth);
   365   }
   366   else if(tree_a) {
   367     minTree();
   368   }
   369   
   370 
   371   std::cout << "Number of nodes    : " << countNodes(g) << std::endl;
   372   std::cout << "Number of edges    : " << countUEdges(g) << std::endl;
   373   double tlen=0;
   374   for(UEdgeIt e(g);e!=INVALID;++e)
   375     tlen+=sqrt((coords[g.source(e)]-coords[g.target(e)]).normSquare());
   376   std::cout << "Total edge length  : " << tlen << std::endl;
   377   if(eps)
   378     graphToEps(g,prefix+".eps").
   379       scale(600).nodeScale(.2).edgeWidthScale(.001).preScale(false).
   380       coords(coords).run();
   381 
   382   UGraphWriter<ListUGraph>(prefix+".lgf",g).
   383     writeNodeMap("coordinates_x",scaleMap(xMap(coords),600)).
   384     writeNodeMap("coordinates_y",scaleMap(yMap(coords),600)).
   385     run();
   386 }
   387