COIN-OR::LEMON - Graph Library

source: lemon-0.x/tools/lgf-gen.cc @ 2446:dd20d76eed13

Last change on this file since 2446:dd20d76eed13 was 2446:dd20d76eed13, checked in by Alpar Juttner, 17 years ago

A minimum spanning tree based TSP algorithm is added (-tsp2)

File size: 12.3 KB
Line 
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
35using namespace lemon;
36
37typedef dim2::Point<double> Point;
38
39UGRAPH_TYPEDEFS(ListUGraph);
40
41bool progress=true;
42
43int N;
44// int girth;
45
46ListUGraph g;
47
48std::vector<Node> nodes;
49ListUGraph::NodeMap<Point> coords(g);
50
51
52double 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
59int tsp_impr_num=0;
60
61const double EPSILON=1e-8;
62bool 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
87bool 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
94void 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
104void tsp()
105{
106  for(int i=0;i<N;i++) g.addEdge(nodes[i],nodes[(i+1)%N]);
107  tsp_improve();
108}
109
110class Line
111{
112public:
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 
121inline std::ostream& operator<<(std::ostream &os, const Line &l)
122{
123  os << l.a << "->" << l.b;
124  return os;
125}
126
127bool 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
135struct Pedge
136{
137  Node a;
138  Node b;
139  double len;
140};
141
142bool pedgeLess(Pedge a,Pedge b)
143{
144  return a.len<b.len;
145}
146
147std::vector<UEdge> edges;
148
149void 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
177void 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
194void 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
213void 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
248void 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
289Node 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
295void 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
375int 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
Note: See TracBrowser for help on using the repository browser.