graph.h
Go to the documentation of this file.
1 /*
2  @copyright Russell Standish 2000-2013
3  @author Russell Standish
4  This file is part of EcoLab
5 
6  Open source licensed under the MIT license. See LICENSE for details.
7 */
8 
12 #ifndef GRAPH_H
13 #define GRAPH_H
14 
15 #include <classdesc_access.h>
16 #include "sparse_mat.h"
17 #include "pack_stl.h"
18 #include "TCL_obj_base.h"
19 #include "arrays.h"
20 #include "poly.h"
21 
22 #include <vector>
23 #include <set>
24 #include <utility>
25 #include <algorithm>
26 #include <iostream>
27 #include <assert.h>
28 
29 #ifdef _CLASSDESC
30 #pragma omit pack ecolab::Graph::back_insert_iterator
31 #pragma omit unpack ecolab::Graph::back_insert_iterator
32 #pragma omit pack ecolab::Graph::const_iterator
33 #pragma omit unpack ecolab::Graph::const_iterator
34 #pragma omit pack ecolab::BiDirectionalGraph::const_iterator
35 #pragma omit unpack ecolab::BiDirectionalGraph::const_iterator
36 #pragma omit pack ecolab::sparse_mat_graph_adaptor::const_iterator
37 #pragma omit unpack ecolab::sparse_mat_graph_adaptor::const_iterator
38 #pragma omit pack ecolab::sparse_mat_graph_adaptor
39 #pragma omit unpack ecolab::sparse_mat_graph_adaptor
40 
41 #endif
42 
43 namespace ecolab
44 {
45  struct Edge: public std::pair<unsigned,unsigned>
46  {
47  typedef std::pair<unsigned,unsigned> super;
48  unsigned& source() {return first;}
49  unsigned& target() {return second;}
50  unsigned source() const {return first;}
51  unsigned target() const {return second;}
52  float weight;
53  Edge(): weight(1) {}
54  template<class S, class T>
55  Edge(S source, T target): super(source, target), weight(1.0) {
56  assert(source!=target);}
57  template<class S, class T, class W>
58  Edge(S source, T target, W weight):
59  super(source, target), weight(weight) {
60  assert(source!=target);}
61 
62  // edges should be unique wrt their connections only.
63  bool operator==(const Edge& e) const {
64  return first==e.first && second==e.second;
65  }
66  bool operator<(const Edge& e) const {
67  return first<e.first || (first==e.first && second<e.second);
68  }
69  };
70 
73  template <class Graph, class BG>
75  public std::iterator<std::output_iterator_tag, void, void, void, void>
76  {
77  Graph& g;
78  const BG& bg;
79  public:
80  Graph_back_insert_iterator(Graph& g, const BG& bg): g(g), bg(bg) {}
82  (const typename BG::edge_iterator::value_type& bge)
83  {
84  g.push_back(Edge(source(bge,bg),target(bge,bg)));
85  return *this;
86  }
87  Graph_back_insert_iterator& operator*() {return *this; }
88  Graph_back_insert_iterator& operator++() {return *this; }
89  };
90 
94  struct Graph
95  {
96  typedef Edge value_type;
97  typedef std::size_t size_type;
98  typedef std::ptrdiff_t difference_type;
99  typedef Edge& reference;
100  typedef const Edge& const_reference;
101 
103  {
104  virtual Edge operator*() const=0;
105  virtual const const_iterator_base& operator++()=0;
106  virtual bool operator==(const const_iterator_base& x) const=0;
107  virtual ~const_iterator_base() {}
108  };
109 
111  class const_iterator: public classdesc::poly<const_iterator_base>,
112  public std::iterator<std::forward_iterator_tag,Edge>
113  {
115  Graph::const_iterator_base& base() {return super::operator*();}
116  const Graph::const_iterator_base& base() const {return super::operator*();}
118  mutable Edge edge; //used for operator->
119  public:
120  Edge operator*() const {
121  return *base();
122  }
123  const Edge* operator->() const {edge=*base(); return &edge;}
124  const_iterator& operator++() {++base(); return *this;}
125  bool operator==(const const_iterator& x) const {return base()==x.base();}
126  bool operator!=(const const_iterator& x) const {return !operator==(x);}
127  };
128 
130  virtual const_iterator begin() const=0;
132  virtual const_iterator end() const=0;
134  virtual unsigned nodes() const=0;
136  virtual unsigned links() const=0;
138  virtual void push_back(const Edge& e)=0;
140  template <class BG> void push_back
141  (const typename BG::edge_iterator::value_type& e)
142  {push_back(Edge(e.first,e.second));}
144  virtual bool contains(const Edge& e) const=0;
146  virtual bool directed() const=0;
148  virtual void clear(unsigned nodes=0)=0;
149  void Clear(TCL_args args) {
150  unsigned nodes=0;
151  if (args.count) nodes=args;
152  clear(nodes);
153  }
154  const Graph& operator=(const Graph& x) {
155  clear(x.nodes());
156  for (const_iterator e=x.begin(); e!=x.end(); ++e)
157  push_back(*e);
158  return *this;
159  }
160  virtual ~Graph() {}
162  void input(const std::string& format, const std::string& filename);
163  void output(const std::string& format, const std::string& filename) const;
165 
168  template <class BG>
170  return Graph_back_insert_iterator<Graph,BG>(*this,bg);
171  }
172  };
173 
174  // define this outside GraphAdaptor to get around classdesc bug.
175  template <class G> struct GraphAdaptor_const_iterator_base:
176  public G::const_iterator,
177  public classdesc::Object<
178  GraphAdaptor_const_iterator_base<G>, Graph::const_iterator_base
179  >
180  {
181  GraphAdaptor_const_iterator_base(const typename G::const_iterator& i):
182  G::const_iterator(i) {}
183  Edge operator*() const {return G::const_iterator::operator*();}
184  const Graph::const_iterator_base& operator++() {
185  G::const_iterator::operator++(); return *this;}
186  bool operator==(const GraphAdaptor_const_iterator_base& x) const {
187  return G::const_iterator::operator==(x);
188  }
189  bool operator==(const Graph::const_iterator_base& x) const {
191  dynamic_cast<const GraphAdaptor_const_iterator_base*>(&x);
192  return xp && operator==(*xp);
193  }
194  };
195 
196 #ifdef _CLASSDESC
197 #pragma omit pack ecolab::Graph::const_iterator_base
198 #pragma omit unpack ecolab::Graph::const_iterator_base
199 #pragma omit pack ecolab::GraphAdaptor_const_iterator_base
200 #pragma omit unpack ecolab::GraphAdaptor_const_iterator_base
201 #pragma omit TCL_obj ecolab::GraphAdaptor_const_iterator_base
202 #pragma omit isa ecolab::GraphAdaptor_const_iterator_base
203 #endif
204 
210 template <class G>
211 class GraphAdaptor: public Graph
212 {
213  G& g;
215 
217  // a bit a mucking around to get this template to work for <const G>
218  template <class GG> void Gpush(GG& g, const Edge& e) {g.push_back(e);}
219  template <class GG> void Gpush(const GG& g, const Edge& e) {}
220  template <class GG> void Gclear(GG& g, unsigned nodes) {g.clear(nodes);}
221  template <class GG> void Gclear(const GG& g, unsigned nodes) {}
222 
223 public:
224  GraphAdaptor(G& g): g(g) {}
225  const GraphAdaptor& operator=(const GraphAdaptor& x) {g=x.g; return *this;}
226 
229  r.addObject<const_iterator_base>(g.begin());
230  return r;
231  }
234  r.addObject<const_iterator_base>(g.end());
235  return r;
236  }
237 
238  unsigned nodes() const {return g.nodes();}
239  unsigned links() const {return g.links();}
240  bool contains(const Edge& e) const {return g.contains(e);}
241  bool directed() const;
242  void push_back(const Edge& e) {Gpush(g,e);}
243  void clear(unsigned nodes=0) {Gclear(g,nodes);}
245 // void input(TCL_args arg) {Graph::input(arg[0], arg[1]);}
246 // void output(TCL_args arg) const {Graph::output(arg[0], arg[1]);}
248 
249 };
250 
251 #ifdef _CLASSDESC
252 //#pragma omit pack GraphAdaptor
253 //#pragma omit unpack GraphAdaptor
254 #endif
255 
256 template <class G>
257 class ConcreteGraph: public GraphAdaptor<G>
258 {
259  G g;
261 public:
262  ConcreteGraph(unsigned nodes=0): GraphAdaptor<G>(g), g(nodes) {}
263  template <class H> ConcreteGraph(const H& g1): GraphAdaptor<G>(g), g(g1) {}
264  bool operator==(const ConcreteGraph& x) {return x.g==g;}
265  bool operator!=(const ConcreteGraph& x) {return x.g!=g;}
266 };
267 
268 // default is not directed
269 template <class G> bool GraphAdaptor<G>::directed() const
270 {return true;}
271 
272 class DiGraph: private std::set<Edge>
273 {
274  unsigned num_nodes;
276 public:
277  typedef std::set<Edge> Evec;
278  // export all const functions of the underlying vector
279  using Evec::size;
280  using Evec::empty;
281  using Evec::begin;
282  using Evec::end;
283  using Evec::value_type;
284  using Evec::size_type;
285  using Evec::difference_type;
286  //using Evec::const_iterator;
287  using Evec::const_reference;
288 
289 #ifdef __APPLE_CC__
290  // bizarrely iterator equality is missing on Apple's compiler!
291  struct const_iterator: public Evec::const_iterator
292  {
293  const_iterator() {}
294  const_iterator(const Evec::const_iterator& x): Evec::const_iterator(x) {}
295  bool operator==(const const_iterator& x) const {return **this==*x;}
296  };
297 #else
298  using Evec::const_iterator;
299 #endif
300 
301  typedef const_iterator iterator; //disallow modification of edges
302 
303  unsigned nodes() const {return num_nodes;}
304  unsigned links() const {return size();}
305  bool contains(const Edge& e) const {return count(e);}
306  DiGraph(unsigned nodes=0): num_nodes(nodes) {}
308  template <class G> DiGraph(const G& g): num_nodes(0) {*this=g;}
309  template <class G> const DiGraph& operator=(const G& g) {
310  clear(g.nodes());
311  for (typename G::const_iterator i=g.begin(); i!=g.end(); ++i) push_back(*i);
312  return *this;
313  }
314  // use push_back for graph construction
315  void push_back(const Edge& e) {
316  if (e.source()>=num_nodes) num_nodes=e.source()+1;
317  if (e.target()>=num_nodes) num_nodes=e.target()+1;
318  Evec::insert(e);
319  }
320  void clear(unsigned nodes=0) {num_nodes=nodes; Evec::clear();}
321  void swap(DiGraph& g) {std::swap(num_nodes,g.num_nodes); Evec::swap(g);}
322  bool operator==(const DiGraph& x) const
323  {return static_cast<const Evec&>(*this)==static_cast<const Evec&>(x);}
324  bool operator!=(const DiGraph& x) const {return !operator==(x);}
325  bool operator<(const DiGraph& x) const
326  {return static_cast<const Evec&>(*this)<static_cast<const Evec&>(x);}
327 };
328 
329 #ifdef _CLASSDESC
330 #pragma omit pack ecolab::DiGraph::const_iterator
331 #pragma omit unpack ecolab::DiGraph::const_iterator
332 #pragma omit TCL_obj ecolab::DiGraph::const_iterator
333 #pragma omit isa ecolab::DiGraph::const_iterator
334 #pragma omit pack ecolab::BiDirectionalGraph_const_iterator
335 #pragma omit unpack ecolab::BiDirectionalGraph_const_iterator
336 #pragma omit TCL_obj ecolab::BiDirectionalGraph_const_iterator
337 #pragma omit isa ecolab::BiDirectionalGraph_const_iterator
338 #endif
339 
341  public std::iterator<std::forward_iterator_tag,Edge>
342 {
343  bool first;
344  DiGraph::const_iterator it;
346  mutable Edge swapped;
347 public:
348  BiDirectionalGraph_const_iterator(const DiGraph::const_iterator& i): first(true), it(i) {}
349  const Edge& operator*() const {
350  if (first) return *it;
351  else
352  {
353  swapped=Edge(it->target(),it->source(), it->weight);
354  return swapped;
355  }
356  }
357  const Edge* operator->() const {return &operator*();}
358 
359  BiDirectionalGraph_const_iterator& operator++()
360  {first=!first; if (first) ++it; return *this;}
361  BiDirectionalGraph_const_iterator operator++(int)
362  {BiDirectionalGraph_const_iterator old(*this); operator++(); return old;}
363  BiDirectionalGraph_const_iterator& operator--()
364  {first=!first; if (!first) --it; return *this;}
365  BiDirectionalGraph_const_iterator operator--(int)
366  {BiDirectionalGraph_const_iterator old(*this); operator--(); return old;}
367  bool operator==(const BiDirectionalGraph_const_iterator& i) const
368  {return first==i.first && it==i.it;}
369  bool operator!=(const BiDirectionalGraph_const_iterator& i) const
370  {return !operator==(i);}
371 };
372 
374 // base class is protected, because viewing this thing as a Graph is not correct
376 {
377  DiGraph graph;
379 public:
380  // iterators return reverse link after normal link
382  typedef const_iterator iterator; // cannot update individual links
383  const_iterator begin() const {return const_iterator(graph.begin());}
384  const_iterator end() const {return const_iterator(graph.end());}
385  // use push_back for graph construction
386  void push_back(Edge e) {
387  if (e.source()>e.target()) std::swap(e.source(),e.target());
388  graph.push_back(e);
389  }
390  void clear(unsigned nodes=0) {graph.clear(nodes);}
391 
392  BiDirectionalGraph(unsigned nodes=0): graph(nodes) {}
394  template <class G> BiDirectionalGraph(const G& g) {*this=g;}
395  template <class G> const BiDirectionalGraph& operator=(const G& g) {
396  clear(g.nodes());
397  for (typename G::const_iterator i=g.begin(); i!=g.end(); ++i) push_back(*i);
398  return *this;
399  }
400  unsigned nodes() const {return graph.nodes();}
401  unsigned links() const {return 2*graph.links();}
402  bool contains(Edge e) const {
403  if (e.source()>e.target()) std::swap(e.source(),e.target());
404  return graph.contains(e);
405  }
406  void swap(BiDirectionalGraph& g) {graph.swap(g.graph);}
407  bool operator==(const BiDirectionalGraph& x) const {return graph==x.graph;}
408  bool operator!=(const BiDirectionalGraph& x) const {return graph!=x.graph;}
409  bool operator<(const BiDirectionalGraph& x) const {return graph<x.graph;}
410 };
411 
412 template <> inline
413 bool GraphAdaptor<BiDirectionalGraph>::directed() const {return false;}
414 
415 // uses the sign of the off-diagonal term to indicate link
416 // direction. Links point in the same direction have their weights
417 // summed
418 class sparse_mat_graph: public ConcreteGraph<DiGraph>
419 {
420 public:
421  const sparse_mat_graph& operator=(const sparse_mat& mat) {
422  clear();
423  std::map<std::pair<size_t, size_t>, double > weights;
424  for (size_t i=0; i<mat.row.size(); ++i) {
425  if (mat.val[i] > 0)
426  weights[std::make_pair(mat.row[i],mat.col[i])]+=mat.val[i];
427  else
428  weights[std::make_pair(mat.col[i],mat.row[i])]-=mat.val[i];
429  }
430  std::map<std::pair<size_t, size_t>, double >::iterator i = weights.begin();
431  for (; i!=weights.end(); ++i)
432  push_back(Edge(i->first.first, i->first.second, i->second));
433  return *this;
434  }
435 };
436 
437 //An adaptor for sparse_mats. Uses absolute values for weights
439 {
440  const sparse_mat& mat;
442 public:
443  sparse_mat_graph_adaptor(const sparse_mat& mat): mat(mat) {}
444 
446  {
447  size_t it;
448  const sparse_mat& mat;
450  mutable Edge link;
451  public:
452  const_iterator(const sparse_mat& mat, size_t it): it(it), mat(mat) {}
453  const Edge& operator*() const
454  {
455  // we're using abs here, as networks need to have positive
456  // weights for compelxity calculations. not sure if we'll
457  // continue with this concept, or adjust it in complexity
458  link=Edge(mat.row[it], mat.col[it], std::abs(mat.val[it]));
459  return link;
460  }
461  const Edge* operator->() const {return &operator*();}
462  const_iterator& operator++() {++it; return *this;}
463  const_iterator operator++(int) {++it; return const_iterator(mat,it-1);}
464  const_iterator& operator--() {--it; return *this;}
465  const_iterator operator--(int) {--it; return const_iterator(mat,it+1);}
466  bool operator==(const const_iterator& i) const {return it==i.it && &mat==&i.mat;}
467  bool operator!=(const const_iterator& i) const {return !operator==(i);}
468  };
469  const_iterator begin() const {return const_iterator(mat,0);}
470  const_iterator end() const {return const_iterator(mat,mat.row.size());}
471 
472  unsigned nodes() const {assert(mat.rowsz==mat.colsz);
473  return mat.diag.size()==0? mat.rowsz: mat.diag.size();}
474  unsigned links() const {return(mat.row.size());}
475  bool contains(const Edge& e) const {
476  for (size_t i=0; i<mat.row.size(); ++i)
477  if (mat.row[i]==e.source() && mat.col[i]==e.target())
478  return true;
479  return false;
480  }
481 };
482 
483 inline void swap(DiGraph& x, DiGraph& y) {x.swap(y);}
484 inline void swap(BiDirectionalGraph& x, BiDirectionalGraph& y) {x.swap(y);}
485 
486 struct Degrees
487 {
488  ecolab::array_ns::array<unsigned> in_degree, out_degree;
489  Degrees(unsigned nodes=0) : in_degree(nodes,0), out_degree(nodes,0) {}
490 };
491 
492 template<class G>
493 Degrees degrees(const G& g)
494 {
495  Degrees d(g.nodes());
496  for (typename G::const_iterator e=g.begin(); e!=g.end(); ++e)
497  {
498  d.in_degree[e->target()]++;
499  d.out_degree[e->source()]++;
500  }
501  return d;
502 }
503 
505 static struct ConstantRNG: public random_gen
506 {
507  double rand() {return 1;}
508 } one;
509 
510 
512 void ErdosRenyi_generate(Graph& g, unsigned nodes, unsigned links, urand& uni,
513  random_gen& weight_dist=one);
514 
518 void PreferentialAttach_generate(Graph& g, unsigned nodes, urand& uni,
519  random_gen& indegree_dist=one, random_gen& weight_dist=one);
520 
522 void random_rewire(Graph& g, urand& u);
523 
524 } // namespace ecolab
525 
526 namespace classdesc_access
527 {
528  template <class G> struct access_pack
529  <ecolab::GraphAdaptor_const_iterator_base<G> >:
530  public classdesc::NullDescriptor<classdesc::pack_t> {};
531 
532  template <class G> struct access_unpack
533  <ecolab::GraphAdaptor_const_iterator_base<G> >:
534  public classdesc::NullDescriptor<classdesc::pack_t> {};
535 }
536 
537 namespace std
538 {
540  std::ostream& operator<<(std::ostream& s, const ecolab::Graph& x);
541  template <class G>
542  std::ostream& operator<<(std::ostream& s, const ecolab::ConcreteGraph<G>& x)
543  {return s<<static_cast<const ecolab::Graph&>(x);}
544 
545  inline std::ostream& operator<<(std::ostream& s, const ecolab::DiGraph& x)
546  {return s<<ecolab::GraphAdaptor<const ecolab::DiGraph>(x);}
547  inline std::ostream& operator<<(std::ostream& s,
549  {return s<<ecolab::GraphAdaptor<const ecolab::BiDirectionalGraph>(x);}
550 
551  std::istream& operator>>(std::istream& s, ecolab::Graph& x);
552  template <class G>
553  std::istream& operator>>(std::istream& s, ecolab::ConcreteGraph<G>& x)
554  {return s>>static_cast<ecolab::Graph&>(x);}
555 
556  inline std::istream& operator>>(std::istream& s, ecolab::DiGraph& x)
557  {ecolab::GraphAdaptor<ecolab::DiGraph> g(x); return s>>g;}
558  inline std::istream& operator>>(std::istream& s, ecolab::BiDirectionalGraph& x)
560 }
561 
562 #if defined(__GNUC__) && !defined(__ICC) && !defined(__clang__)
563 #pragma GCC diagnostic push
564 #pragma GCC diagnostic ignored "-Wunused-local-typedefs"
565 #endif
566 
567 #include "graph.cd"
568 
569 #if defined(__GNUC__) && !defined(__ICC) && !defined(__clang__)
570 #pragma GCC diagnostic pop
571 #endif
572 #endif
descriptor access to a class&#39;s privates
sparse matrix class
Definition: sparse_mat.h:20
virtual const_iterator begin() const =0
iterator to first edge
virtual void push_back(const Edge &e)=0
add an edge. Node count is adjusted so that edge is valid.
bool contains(const Edge &e) const
true if graph contains e
Definition: graph.h:240
unsigned links() const
number of links
Definition: graph.h:239
Definition: poly.h:43
Sparse matrices.
iterator over edges
Definition: graph.h:111
Graph::const_iterator begin() const
iterator to first edge
Definition: graph.h:227
virtual unsigned nodes() const =0
number of nodes
Definition: graph.h:272
Definition: graph.h:537
Definition: graph.h:486
unsigned nodes() const
number of nodes
Definition: graph.h:238
A graph in which each link is bidirectional.
Definition: graph.h:375
void ErdosRenyi_generate(Graph &g, unsigned nodes, unsigned links, urand &uni, random_gen &weight_dist=one)
random graph chosen uniformly from the set of graphs with n nodes and l links
Definition: graph.h:438
DiGraph(const G &g)
initialise Graph using Graph "duck-typed" object
Definition: graph.h:308
void push_back(const Edge &e)
add an edge. Node count is adjusted so that edge is valid.
Definition: graph.h:242
Definition: graph.h:257
abstract base class for representing random number generators
Definition: random.h:32
bool directed() const
true if a bidirectional graph (all edges go both ways)
Definition: graph.h:269
void clear(unsigned nodes=0)
remove all edges from the graph and set the node count
Definition: graph.h:243
class to allow access to private members
Definition: classdesc_access.h:21
dynamic array class
Definition: graph.h:211
Definition: graph.h:94
helper for constructing null descriptors
Definition: classdesc.h:784
poly addObject()
Target object initialisation.
Definition: poly.h:68
Definition: graph.h:418
class to allow access to private members
Definition: classdesc_access.h:22
#define CLASSDESC_ACCESS(type)
add friend statements for each accessor function
Definition: classdesc_access.h:36
void random_rewire(Graph &g, urand &u)
randomly rewire the graph g (in place), using random generator u
Graph_back_insert_iterator< Graph, BG > back_inserter(const BG &bg)
Definition: graph.h:169
Definition: object.h:28
Represent arguments to TCL commands.
Definition: TCL_obj_base.h:138
BiDirectionalGraph(const G &g)
initialise Graph using Graph "duck-typed" object
Definition: graph.h:394
TCL access descriptor.
Definition: object.h:76
void PreferentialAttach_generate(Graph &g, unsigned nodes, urand &uni, random_gen &indegree_dist=one, random_gen &weight_dist=one)
serialisation for standard containers
size_t size() const
number of elements
Definition: arrays.h:1766
_OPENMP
Definition: accessor.h:16
virtual const_iterator end() const =0
iterator beyond last edge
Definition: graph.h:102
Contains access_* structs, and nothing else. These structs are used to gain access to private members...
Definition: accessor.h:55
Definition: random_basic.h:11
Definition: graph.h:45
Graph::const_iterator end() const
iterator beyond last edge
Definition: graph.h:232