graphcode.h
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 
9 #ifndef GRAPHCODE_H
10 #define GRAPHCODE_H
11 
15 #ifndef MAP
16 #define MAP hmap
17 #endif
18 
19 #undef x1str
20 #define x1str(x) #x
21 #undef xstr
22 #define xstr(x) x1str(x)
23 #undef cat
24 #define cat(x,y) x##y
25 #undef xcat
26 #define xcat(x,y) cat(x,y)
27 
29 #undef GRAPHCODE_NS
30 #define GRAPHCODE_NS xcat(graphcode_,MAP)
31 
32 #ifdef MPI_SUPPORT
33 #include <classdescMP.h>
34 
35 #ifdef PARMETIS
36 /* Metis stuff */
37 extern "C" void METIS_PartGraphRecursive
38 (unsigned* n,unsigned* xadj,unsigned* adjncy,unsigned* vwgt,unsigned* adjwgt,
39  unsigned* wgtflag,unsigned* numflag,unsigned* nparts,unsigned* options,
40  unsigned* edgecut, unsigned* part);
41 extern "C" void METIS_PartGraphKway
42 (unsigned* n,unsigned* xadj,unsigned* adjncy,unsigned* vwgt,unsigned* adjwgt,
43  unsigned* wgtflag,unsigned* numflag,unsigned* nparts,unsigned* options,
44  unsigned* edgecut, unsigned* part);
45 
46 #include <parmetis.h>
47 #else
48 typedef int idxtype; /* just for defining dummy weight functions */
49 #endif
50 
51 #else
52 typedef int idxtype; /* just for defining dummy weight functions */
53 #endif /* MPI_SUPPORT */
54 
55 #include <vector>
56 #include <map>
57 #include <algorithm>
58 #include <iostream>
59 
60 #ifdef ECOLAB_LIB
61 #include "TCL_obj_base.h"
62 #endif
63 
64 #include <vector>
65 #include <set>
66 #include <algorithm>
67 #include <iostream>
68 
69 #include <classdesc_access.h>
70 #include <object.h>
71 #include <pack_base.h>
72 #include <pack_stl.h>
73 
74 namespace GRAPHCODE_NS
75 {
77  typedef unsigned long GraphID_t;
80  const GraphID_t bad_ID=~0UL;
81 
82  using std::vector;
83  using std::map;
84  using std::set;
85  using std::find_if;
86  using std::find;
87  using std::cout;
88  using std::endl;
89  using namespace classdesc;
90  using classdesc::string;
91 
92 #ifdef MPI_SUPPORT
93  /* MPI_Finalized only available in MPI-2 standard */
94  inline bool MPI_running()
95  {
96  int fi, ff=0; MPI_Initialized(&fi);
97 #if (defined(MPI_VERSION) && MPI_VERSION>1 || defined(MPICH_NAME))
98  MPI_Finalized(&ff);
99 #endif /* MPI_VERSION>1 */
100  return fi&&!ff;
101  }
102 #endif /* MPI_SUPPORT */
103 
105  inline unsigned myid()
106  {
107  int m=0;
108 #ifdef MPI_SUPPORT
109  if (MPI_running()) MPI_Comm_rank(MPI_COMM_WORLD,&m);
110 #endif
111  return m;
112  }
113 
115  inline unsigned nprocs()
116  {
117  int m=1;
118 #ifdef MPI_SUPPORT
119  if (MPI_running()) MPI_Comm_size(MPI_COMM_WORLD,&m);
120 #endif
121  return m;
122  }
123 
127  template <typename TYPE>
128  inline TYPE Wrap(TYPE val, TYPE limit)
129  {
130  if( val >= limit )
131  return val-limit;
132  else if( val < 0 )
133  return val+limit;
134  else
135  return val;
136  }
137 
138 
139  class object;
140  class omap;
141  class Graph;
142 
143  /* base object of graphcode - can be a pin or a wire - whatever */
145  class objref
146  {
147  object *payload; /* referenced data */
148  bool managed;
149  friend class omap;
151  public:
152  GraphID_t ID;
153  unsigned int proc;
154 
155  struct id_eq /*predicate function testing whether x's ID is a given value*/
156  {
157  GraphID_t id;
158  id_eq(GraphID_t i): id(i) {}
159  bool operator()(const objref& x) {return x.ID==id;}
160  };
161 
162  objref(GraphID_t i=0, int p=myid(), object *o=NULL):
163  payload(o), managed(false), ID(i), proc(p) {}
164  objref(GraphID_t i, int p, object &o):
165  payload(&o), managed(false), ID(i), proc(p) {}
166  objref(const objref& x): payload(NULL) {*this=x;}
167  ~objref() {nullify();}
168  inline objref& operator=(const objref& x);
169  object& operator*() {assert(payload!=NULL); return *payload;}
170  object* operator->() {assert(payload!=NULL); return payload;}
171  const object& operator*() const {assert(payload!=NULL); return *payload;}
172  const object* operator->() const {assert(payload!=NULL); return payload;}
176  void addref(object* o, bool mflag=false)
177  {nullify(); payload=o; managed=mflag;}
178  bool nullref() const {return payload==NULL;}
179  inline void nullify();
180  };
181 
182 #include xstr(MAP)
183 
187  class omap: public MAP
188  {
189  objref bad_thing;
190  public:
191  omap() {bad_thing.ID=bad_ID;}
192  inline objref& operator[](GraphID_t i);
193  inline omap& operator=(const omap& x);
194  };
195 
196 
197  inline omap& objectMap()
198  {
199  static omap o;
200  return o;
201  }
202 
209  class Ptrlist
210  {
211  vector<objref*> list;
212  friend class omap;
213  friend class Graph;
214  friend void unpack(pack_t*,const string&,objref&);
215  public:
216  typedef vector<objref*>::size_type size_type;
217 
218  class iterator: public std::iterator<std::random_access_iterator_tag,objref>
219  {
220  typedef vector<objref*>::const_iterator vec_it;
221  vec_it iter;
222  public:
223  iterator& operator=(const vec_it& x) {iter=x; return *this;}
224  iterator() {}
225  iterator(const iterator& x) {iter=x.iter;}
226  iterator(vec_it x) {iter=x;}
227  objref& operator*() {return **iter;}
228  objref* operator->() {return *iter;}
229  iterator operator++() {return iterator(++iter);}
230  iterator operator--() {return iterator(--iter);}
231  iterator operator++(int) {return iterator(iter++);}
232  iterator operator--(int) {return iterator(iter--);}
233  bool operator==(const iterator& x) const {return x.iter==iter;}
234  bool operator!=(const iterator& x) const {return x.iter!=iter;}
235  size_t operator-(const iterator& x) const {return iter-x.iter;}
236  iterator operator+(size_t x) const {return iterator(iter+x);}
237  };
238  iterator begin() const {return iterator(list.begin());}
239  iterator end() const {return iterator(list.end());}
240  objref& front() {return *list.front();}
241  objref& back() {return *list.back();}
242  const objref& front() const {return *list.front();}
243  const objref& back() const {return *list.back();}
244  objref& operator[](unsigned i) const
245  {
246  assert(i<list.size());
247  return *list[i];
248  }
249  void push_back(objref* x)
250  {
251  if (x->ID!=bad_ID)
252  list.push_back(&objectMap()[x->ID]);
253  }
254  void push_back(objref& x) {push_back(&x);}
255  void erase(GraphID_t i)
256  {
257  vector<objref*>::iterator it;
258  for (it=list.begin(); it!=list.end(); it++) if ((*it)->ID==i) break;
259  if ((*it)->ID==i) list.erase(it);
260  }
261  void clear() {list.clear();}
262  size_type size() const {return list.size();}
263  Ptrlist& operator=(const Ptrlist &x)
264  {
265  /* assignment of these refs must also fix up pointers to be consistent
266  with the map */
267  list.resize(x.size());
268  for (size_type i=0; i<size(); i++)
269  list[i]=&objectMap()[x[i].ID];
270  return *this;
271  }
272  void lpack(pack_t& targ) const
273  {
274  targ<<size();
275  for (iterator i=begin(); i!=end(); i++) targ << i->ID;
276  }
277  void lunpack(pack_t& targ)
278  {
279  clear();
280  size_type size; targ>>size;
281  for (unsigned i=0; i<size; i++)
282  {
283  GraphID_t id; targ>>id;
284  push_back(&objectMap()[id]);
285  }
286  }
287  };
288 
289 
295  class object: public Ptrlist, virtual public classdesc::object
296  {
297  public:
298 #ifdef TCL_OBJ_BASE_H
299  virtual void TCL_obj(const classdesc::string& d) {}
301 #endif
302  virtual ~object() {}
303  virtual idxtype weight() const {return 1;}
304  virtual idxtype edgeweight(const objref& x) const {return 1;}
306  };
307 
308  /*
309  the #ifdef causes classdesc grief.
310  */
311 
312  inline void objref::nullify()
313  {
314  if (managed) delete payload;
315  managed=false; payload=NULL;
316  }
317 
318  inline objref& objref::operator=(const objref& x)
319  {
320  nullify();
321  ID=x.ID; proc=x.proc;
322  if (x.managed && x.payload)
323  {
324  payload=dynamic_cast<object*>(x->clone());
325  managed=true;
326  }
327  else
328  {
329  payload=x.payload;
330  managed=false;
331  }
332  return *this;
333  }
334 
335  inline objref& omap::operator[](GraphID_t i)
336  {
337  if (i==bad_ID)
338  return bad_thing;
339  else
340  {
341  objref& o=at(i);
342  o.ID=i; /* enforce consistent ID field */
343  return o;
344  }
345  }
346 
347  inline omap& omap::operator=(const omap& x)
348  {
349  clear();
350  for (const_iterator i=x.begin(); i!=x.end(); i++)
351  {
352  objref& o=at(i->ID);
353  o.ID=i->ID; o.proc=i->proc;
354  if (!i->nullref())
355  {
356  if (o.nullref() ||o->type()!=(*i)->type())
357  /* we need to create a new object */
358  o.addref(dynamic_cast<object*>((*i)->clone()),true);
359  }
360  else
361  o.nullify();
362  }
363  return *this;
364  }
365 
369  class Graph: public Ptrlist
370  {
371  // CLASSDESC_ACCESS(class GRAPHCODE_NS::Graph);
372 
373  public: //(should be) private:
374  vector<vector<GraphID_t> > rec_req;
375  vector<vector<GraphID_t> > requests;
376  unsigned tag; /* tag used to ensure message groups do not overlap */
377  bool type_registered(const object& x) {return x.type()>=0;}
378 
379  public:
380  omap& objects;
381  Graph(): tag(0), objects(objectMap()) {}
382  Graph(Graph& g): objects(objectMap()) {*this=g;}
383 
384  Graph& operator=(const Graph& x)
385  {
386  static_cast<Ptrlist>(*this)=x; //Why is this needed?
387  rec_req=x.rec_req;
388  requests=x.requests;
389  tag=x.tag;
390  rebuild_local_list();
391  return *this;
392  }
393 
398  {
399  clear();
400  for (omap::iterator p=objectMap().begin(); p!=objectMap().end(); p++)
401  if (p->proc==myid()) Ptrlist::push_back(*p);
402  }
403 
408  {
409  for (omap::iterator i=objectMap().begin(); i!=objectMap().end(); i++)
410  if (i->proc!=myid()) i->nullify();
411  }
412 
416  void print(unsigned proc)
417  {
418  if (proc==myid())
419  for (iterator i=begin(); i!=end(); i++)
420  {
421  std::cout << " i->ID="<<i->ID<<":";
422  for (object::iterator j=(*i)->begin(); j!=(*i)->end(); j++)
423  std::cout << j->ID <<",";
424  std::cout << std::endl;
425  }
426  }
427 
428 
429  /* these method must be called on all processors simultaneously */
430  void gather();
431 
435  void Prepare_Neighbours(bool cache_requests=false);
436  void Partition_Objects();
437 
441  inline void Distribute_Objects();
442 
446  objref& AddObject(object* o, GraphID_t id, bool managed=false)
447  {
448  objref& p=objectMap()[id];
449  o->type(); /* ensure type is registered */
450  p.addref(o,managed);
451  assert(type_registered(*o));
452  return p;
453  }
454  objref& AddObject(object& p, GraphID_t id) {return AddObject(&p,id);}
459  template <class T>
460  objref& AddObject(GraphID_t id)
461  {
462  object* o=new T;
463  return AddObject(o,id,true);
464  }
468  template <class T>
469  objref& AddObject(const T& master_copy, GraphID_t id)
470  {
471  object* o=new T(master_copy);
472  return AddObject(o,id,true);
473  }
474 
475  };
476 
477 
478  inline void
480  {
481 #ifdef MPI_SUPPORT
482  rec_req.clear();
483  MPIbuf() << objectMap() << bcast(0) >> objectMap();
484  rebuild_local_list();
485 #endif
486  }
487 
488 };
489 
490 /* export pack/unpack routines */
491 //using GRAPHCODE_NS::pack;
492 //using GRAPHCODE_NS::unpack;
493 
494 #ifdef _CLASSDESC
495 #pragma omit pack GRAPHCODE_NS::omap
496 #pragma omit unpack GRAPHCODE_NS::omap
497 #pragma omit isa GRAPHCODE_NS::omap
498 #pragma omit pack GRAPHCODE_NS::omap::iterator
499 #pragma omit unpack GRAPHCODE_NS::omap::iterator
500 #pragma omit isa GRAPHCODE_NS::omap::iterator
501 #pragma omit pack GRAPHCODE_NS::Ptrlist
502 #pragma omit unpack GRAPHCODE_NS::Ptrlist
503 #pragma omit pack GRAPHCODE_NS::Ptrlist::iterator
504 #pragma omit unpack GRAPHCODE_NS::Ptrlist::iterator
505 #pragma omit pack GRAPHCODE_NS::object
506 #pragma omit unpack GRAPHCODE_NS::object
507 #pragma omit pack GRAPHCODE_NS::objref
508 #pragma omit unpack GRAPHCODE_NS::objref
509 #pragma omit isa GRAPHCODE_NS::objref
510 #endif
511 
512 namespace classdesc_access
513 {
514  namespace cd=classdesc;
515 
516  template <>
518  {
519  template <class U>
520  void operator()(cd::pack_t& t,const cd::string& d, U& a)
521  {pack(t,d,static_cast<const GRAPHCODE_NS::Ptrlist&>(a));}
522  };
523 
524  template <>
526  {
527  template <class U>
528  void operator()(cd::pack_t& t,const cd::string& d, U& a)
530  };
531 
532  template <>
533  struct access_pack<GRAPHCODE_NS::omap>
534  {
535  template <class U>
536  void operator()(cd::pack_t& buf, const cd::string& desc, U& arg)
537  {
538  buf << arg.size();
539  for (typename U::iterator i=arg.begin(); i!=arg.end(); i++)
540  buf << i->ID << *i;
541  }
542  };
543 
544  template <>
546  {
547  template <class U>
548  void operator()(cd::pack_t& buf, const cd::string& desc, U& arg)
549  {
550  typename U::size_type sz; buf>>sz;
551  GRAPHCODE_NS::GraphID_t ID;
552  for (; sz>0; sz--)
553  {
554  buf>>ID;
555  buf>>arg[ID];
556  }
557  }
558  };
559 
560  template <>
561  struct access_pack<GRAPHCODE_NS::Ptrlist>
562  {
563  template <class U>
564  void operator()(cd::pack_t& targ, const cd::string& desc, U& arg)
565  {arg.lpack(targ);}
566  };
567 
568  template <>
569  struct access_unpack<GRAPHCODE_NS::Ptrlist>
570  {
571  template <class U>
572  void operator()(cd::pack_t& targ, const cd::string& desc, U& arg)
573  {arg.lunpack(targ);}
574  };
575 
576 #ifdef TCL_OBJ_BASE_H
577  /* support for EcoLab TCL_obj method */
578 #ifdef _CLASSDESC
579 #pragma omit TCL_obj GRAPHCODE_NS::object
580 #pragma omit pack classdesc_access::access_TCL_obj
581 #pragma omit unpack classdesc_access::access_TCL_obj
582 #endif
583  template <>
584  struct access_TCL_obj<GRAPHCODE_NS::object>
585  {
586  template <class U>
587  void operator()(cd::TCL_obj_t& targ, const cd::string& desc,U& arg)
588  {
589  static bool not_in_virt=true; // possible thread safety problem
590  if (not_in_virt)
591  {
592  TCL_obj(targ,desc+"",cd::base_cast<GRAPHCODE_NS::Ptrlist>::cast(arg));
593  TCL_obj(targ,desc+".type",arg,&GRAPHCODE_NS::object::type);
594  TCL_obj(targ,desc+".weight",arg,&GRAPHCODE_NS::object::weight);
595  not_in_virt=false;
596  arg.TCL_obj(desc); //This will probably recurse
597  not_in_virt=true;
598  }
599  }
600  };
601 #endif
602 
603  template <>
604  struct access_pack<GRAPHCODE_NS::objref>
605  {
606  template <class U>
607  void operator()(cd::pack_t& targ, const cd::string& desc, U& arg)
608  {
609  ::pack(targ,desc,arg.ID);
610  ::pack(targ,desc,arg.proc);
611  if (arg.nullref())
612  targ<<-1;
613  else
614  {
615  ::pack(targ,desc,arg->type());
616  arg->pack(targ);
617  }
618  }
619  };
620 
621  template <>
622  struct access_unpack<GRAPHCODE_NS::objref>
623  {
624  template <class U>
625  void operator()(cd::pack_t& targ, const cd::string& desc, U& arg)
626  {
627  ::unpack(targ,desc,arg.ID);
628  ::unpack(targ,desc,arg.proc);
629  int t; targ>>t;
630  if (t<0)
631  {
632  arg.nullify();
633  return;
634  }
635  else if (arg.nullref() || arg->type()!=t)
636  {
637  arg.nullify();
638  cd::object* newobj=cd::object::create(t);
639  GRAPHCODE_NS::object* obj=dynamic_cast<GRAPHCODE_NS::object*>(newobj);
640  if (obj)
641  arg.addref(obj,true);
642  else
643  {
644  delete newobj; //invalid object heirarchy
645  return;
646  }
647  }
648  arg->unpack(targ);
649  }
650  };
651 }
652 
653 #undef str
654 #undef xstr
655 
656 #endif /* GRAPHCODE_H */
unsigned int proc
location of object
Definition: graphcode.h:153
descriptor access to a class&#39;s privates
Definition: graphcode.h:295
Definition: graphcode.h:218
unsigned myid
main window of application
Definition: classdesc.h:794
size_t size() const
size of buffer
Definition: pack_base.h:154
MPIbuf manipulator to broadcast the MPIbuf&#39;s contents to all processes.
Definition: classdescMP.h:58
void nullify()
is reference invalid?
Definition: graphcode.h:312
Definition: graphcode.h:155
buffer object providing MPI functionality
Definition: classdescMP.h:75
objref & AddObject(const T &master_copy, GraphID_t id)
Definition: graphcode.h:469
serialisation descriptor
Definition: graphcode.h:187
objref & AddObject(GraphID_t id)
Definition: graphcode.h:460
Definition: graphcode.h:209
class to allow access to private members
Definition: classdesc_access.h:21
virtual idxtype weight() const
Definition: graphcode.h:303
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
Definition: object.h:28
void rebuild_local_list()
Definition: graphcode.h:397
Definition: graphcode.h:369
TCL access descriptor.
GraphID_t ID
object&#39;s ID
Definition: graphcode.h:152
serialisation for standard containers
Definition: TCL_obj_base.h:364
MPI parallel processing library.
Contains definitions related to classdesc functionality.
Definition: arrays.h:2514
Definition: pack_base.h:124
TCL_obj descriptor object.
Definition: TCL_obj_base.h:327
void print(unsigned proc)
Definition: graphcode.h:416
Definition: graphcode.h:74
objref & AddObject(object *o, GraphID_t id, bool managed=false)
Definition: graphcode.h:446
Contains access_* structs, and nothing else. These structs are used to gain access to private members...
Definition: accessor.h:55
void Distribute_Objects()
Definition: graphcode.h:479
Definition: graphcode.h:145
void addref(object *o, bool mflag=false)
Definition: graphcode.h:176
void clear_non_local()
Definition: graphcode.h:407
void unpack(unpack_t &targ, const string &desc, is_treenode dum, T *&arg)
unserialise a tree.
Definition: pack_graph.h:44