vq3
vq3Graph.hpp
1 /*
2  * Copyright (C) 2018, CentraleSupelec
3  *
4  * Author : HervĂ© Frezza-Buet
5  *
6  * Contributor :
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public
10  * License (GPL) as published by the Free Software Foundation; either
11  * version 3 of the License, or any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  *
22  * Contact : herve.frezza-buet@centralesupelec.fr
23  *
24  */
25 
26 
27 
28 
29 #pragma once
30 
31 #include <memory>
32 #include <list>
33 #include <utility>
34 #include <atomic>
35 #include <iostream>
36 #include <map>
37 #include <functional>
38 
39 
40 namespace vq3 {
41 
42  template<typename PAIR>
43  bool invalid_extremities(const PAIR& p) {return p.first == nullptr || p.second == nullptr;}
44 
45  template<typename PAIR>
46  auto& other_extremity(const PAIR& p, const typename PAIR::first_type& me) {
47  if(me == p.second)
48  return p.first;
49  return p.second;
50  }
51 
52  template<typename VERTEX_VALUE, typename EDGE_VALUE> class graph;
53  template<typename VERTEX_VALUE, typename EDGE_VALUE> class graph_;
54  template<typename VERTEX_VALUE, typename EDGE_VALUE> class vertex;
55  template<typename VERTEX_VALUE, typename EDGE_VALUE> class edge;
56 
57  template<typename VERTEX_VALUE, typename EDGE_VALUE>
58  class graph_element {
59  protected:
60 
61  friend class graph_<VERTEX_VALUE, EDGE_VALUE>;
62 
63  std::atomic_bool killed;
64 
65  graph_element() : killed(false) {}
66 
67  public:
68 
69  graph_element(const graph_element&) = delete;
70  graph_element& operator=(const graph_element&) = delete;
71 
76  void kill() {killed = true;}
77 
81  bool is_killed() {return killed;}
82  };
83 
84  template<typename VALUE, typename VERTEX_VALUE, typename EDGE_VALUE>
85  class valued_graph_element : public graph_element<VERTEX_VALUE, EDGE_VALUE> {
86  protected:
87 
88  VALUE v;
89 
92 
93  public:
94 
95  using value_type = VALUE;
96 
98  valued_graph_element& operator=(const valued_graph_element&) = delete;
99 
100  VALUE& operator()() {return v;}
101  const VALUE& operator()() const {return v;}
102  };
103 
104  template<typename VERTEX_VALUE, typename EDGE_VALUE>
105  class valued_graph_element<void, VERTEX_VALUE, EDGE_VALUE> : public graph_element<VERTEX_VALUE, EDGE_VALUE> {
106  protected:
107 
109 
110  public:
111 
112  using value_type = void;
113 
115  valued_graph_element& operator=(const valued_graph_element&) = delete;
116  };
117 
118 
119  template<typename VERTEX_VALUE, typename EDGE_VALUE>
120  class vertex : public valued_graph_element<VERTEX_VALUE, VERTEX_VALUE, EDGE_VALUE> {
121  private:
122 
123  friend class graph_<VERTEX_VALUE, EDGE_VALUE>;
124  friend class graph<VERTEX_VALUE, EDGE_VALUE>;
125 
126  std::list<std::weak_ptr<edge<VERTEX_VALUE, EDGE_VALUE> > > E;
127  bool garbaging = true;
128 
129  vertex(const VERTEX_VALUE& v) : valued_graph_element<VERTEX_VALUE, VERTEX_VALUE, EDGE_VALUE>(v), E() {}
130 
131 
132  template<typename EDGE_FUN>
133  void foreach_edge_garbaging_on(const EDGE_FUN& fun) {
134  auto it = E.begin();
135  while(it != E.end()) {
136  auto e = it->lock();
137  if(e == nullptr || e->is_killed())
138  it = E.erase(it);
139  else {
140  fun(e);
141  if(e->is_killed())
142  it = E.erase(it);
143  else
144  ++it;
145  }
146  }
147  }
148 
149  template<typename EDGE_FUN>
150  void foreach_edge_garbaging_off(const EDGE_FUN& fun) {
151  for(auto& wp : E)
152  if(auto e = wp.lock(); e && !(e->is_killed()))
153  fun(e);
154  }
155 
156  public:
157 
158  using edge_val_type = EDGE_VALUE;
159  using ref_edge_type = std::shared_ptr<edge<VERTEX_VALUE, EDGE_VALUE> >;
160 
161  vertex() = delete;
162  vertex(const vertex&) = delete;
163  vertex& operator=(const vertex&) = delete;
164 
165  template<typename EDGE_FUN>
166  void foreach_edge(const EDGE_FUN& fun) {
167  if(garbaging) foreach_edge_garbaging_on(fun);
168  else foreach_edge_garbaging_off(fun);
169  }
170  };
171 
172  template<typename VERTEX_VALUE, typename EDGE_VALUE>
173  class edge : public valued_graph_element<EDGE_VALUE, VERTEX_VALUE, EDGE_VALUE> {
174  private:
175 
176  friend class graph<VERTEX_VALUE, EDGE_VALUE>;
177  friend class graph_<VERTEX_VALUE, EDGE_VALUE>;
178 
179  std::weak_ptr<vertex<VERTEX_VALUE, EDGE_VALUE> > v1, v2;
180 
181  edge(const std::shared_ptr<vertex<VERTEX_VALUE, EDGE_VALUE> >& v1, const std::shared_ptr<vertex<VERTEX_VALUE, EDGE_VALUE> >& v2, const EDGE_VALUE& v) : valued_graph_element<EDGE_VALUE, VERTEX_VALUE, EDGE_VALUE>(v), v1(v1), v2(v2) {}
182 
183  public:
184 
185  using vertex_val_type = VERTEX_VALUE;
186 
187  edge() = delete;
188  edge(const edge&) = delete;
189  edge& operator=(const edge&) = delete;
190 
191  auto extremities() {
192  auto res = std::make_pair(v1.lock(), v2.lock());
193  if(res.first != nullptr && res.first->is_killed())
194  res.first = nullptr;
195  if(res.second != nullptr && res.second->is_killed())
196  res.second = nullptr;
197  return res;
198  }
199  };
200 
201  template<typename VERTEX_VALUE>
202  class edge<VERTEX_VALUE, void> : public valued_graph_element<void, VERTEX_VALUE, void> {
203  private:
204 
205  friend class graph_<VERTEX_VALUE, void>;
206  friend class graph<VERTEX_VALUE, void>;
207 
208  std::weak_ptr<vertex<VERTEX_VALUE, void> > v1, v2;
209 
210  edge(const std::shared_ptr<vertex<VERTEX_VALUE, void> >& v1, const std::shared_ptr<vertex<VERTEX_VALUE, void> >& v2) : valued_graph_element<void, VERTEX_VALUE, void>(), v1(v1), v2(v2) {}
211 
212  public:
213 
214  using vertex_val_type = VERTEX_VALUE;
215 
216  edge() = delete;
217  edge(const edge&) = delete;
218  edge& operator=(const edge&) = delete;
219 
220  auto extremities() {
221  auto res = std::make_pair(v1.lock(), v2.lock());
222  if(res.first != nullptr && res.first->is_killed())
223  res.first = nullptr;
224  if(res.second != nullptr && res.second->is_killed())
225  res.second = nullptr;
226  return res;
227  }
228  };
229 
230 
231  template<typename VERTEX_VALUE, typename EDGE_VALUE>
232  class graph_ {
233  public:
234 
235  using vertex_type = vertex<VERTEX_VALUE, EDGE_VALUE>;
236  using vertex_value_type = VERTEX_VALUE;
237  using ref_vertex = std::shared_ptr<vertex_type>;
238 
239  using edge_type = edge<VERTEX_VALUE, EDGE_VALUE>;
240  using edge_value_type = EDGE_VALUE;
241  using ref_edge = std::shared_ptr<edge_type>;
242 
243  using wref_vertex = std::weak_ptr<vertex_type>;
244  using wref_edge = std::weak_ptr<edge_type>;
245  using vertices = std::list<ref_vertex>;
246  using edges = std::list<ref_edge>;
247  using weak_vertices = std::list<wref_vertex>;
248  using weak_edges = std::list<wref_edge>;
249 
250  private:
251 
252  vertices V;
253 
254  protected :
255 
256  edges E;
257 
258  private :
259 
260  bool garbaging = true;
261 
262  template<typename VERTEX_FUN>
263  void foreach_vertex_garbaging_on(const VERTEX_FUN& fun) {
264  auto it = V.begin();
265  while(it != V.end()) {
266  auto& v = *it;
267  if(v == nullptr || v->is_killed())
268  it = V.erase(it);
269  else {
270  fun(v);
271  if(v->is_killed())
272  it = V.erase(it);
273  else
274  ++it;
275  }
276  }
277  }
278 
279  template<typename VERTEX_FUN>
280  void foreach_vertex_garbaging_off(const VERTEX_FUN& fun) {
281  for(auto& v : V)
282  if(v && !(v->is_killed()))
283  fun(v);
284  }
285 
286  template<typename EDGE_FUN>
287  void foreach_edge_garbaging_on(const EDGE_FUN& fun) {
288  auto it = E.begin();
289  while(it != E.end()) {
290  auto& e = *it;
291  if(e == nullptr || e->is_killed())
292  it = E.erase(it);
293  else {
294  fun(e);
295  if(e->is_killed())
296  it = E.erase(it);
297  else
298  ++it;
299  }
300  }
301  }
302 
303  template<typename EDGE_FUN>
304  void foreach_edge_garbaging_off(const EDGE_FUN& fun) {
305  for(auto& e : E)
306  if(e && !(e->is_killed()))
307  fun(e);
308  }
309 
310 
311  public:
315  std::vector<ref_vertex> heap;
316 
317  graph_() = default;
318  graph_(const graph_&) = delete;
319  graph_& operator=(const graph_&) = delete;
320 
324  unsigned int nb_vertices() {
325  unsigned int res = 0;
326  this->foreach_vertex([&res](const ref_vertex&) {++res;});
327  return res;
328  }
329 
333  unsigned int nb_edges() {
334  unsigned int res = 0;
335  this->foreach_edge([&res](const ref_edge& ref_e) {
336  auto extr_pair = ref_e->extremities();
337  if(vq3::invalid_extremities(extr_pair)) {
338  ref_e->kill();
339  return;
340  }
341  ++res;
342  });
343  return res;
344  }
345 
349  ref_vertex operator+=(const vertex_value_type& v) {
350  auto res = ref_vertex(new vertex_type(v)); // no std::make_shared since constructor is private.
351  V.push_back(res);
352  return res;
353  return nullptr;
354  }
355 
359  ref_edge get_edge(const ref_vertex& v1, const ref_vertex& v2) const {
360  ref_vertex v, vv;
361 
362  if(v1->E.size() > v2->E.size()) {
363  v = v2;
364  vv = v1;
365  }
366  else {
367  v = v1;
368  vv = v2;
369  }
370 
371  for(auto& we : v->E) {
372  auto e = we.lock();
373  if(e != nullptr) {
374  auto ref_v1 = e->v1.lock();
375  if(ref_v1 != nullptr) {
376  auto ref_v2 = e->v2.lock();
377  if(ref_v2 != nullptr && (ref_v1 == vv || ref_v2 == vv))
378  return e;
379  }
380  }
381  }
382 
383  return nullptr;
384  }
385 
386  template<typename VERTEX_FUN>
387  void foreach_vertex(const VERTEX_FUN& fun) {
388  if(garbaging) foreach_vertex_garbaging_on(fun);
389  else foreach_vertex_garbaging_off(fun);
390  }
391 
392  template<typename EDGE_FUN>
393  void foreach_edge(const EDGE_FUN& fun) {
394  if(garbaging) foreach_edge_garbaging_on(fun);
395  else foreach_edge_garbaging_off(fun);
396  }
397 
402  void garbaging_lock() {
403  garbaging = false;
404  foreach_vertex_garbaging_on([](const ref_vertex& ref_v) {ref_v->garbaging = false;});
405  }
406 
415  garbaging = true;
416  foreach_vertex_garbaging_on([](const ref_vertex& ref_v) {ref_v->garbaging = true;});
417  }
418 
430  foreach_edge_garbaging_on([](const ref_edge& ref_e) {
431  if(auto extr_pair = ref_e->extremities(); vq3::invalid_extremities(extr_pair))
432  ref_e->kill();
433  });
434 
435  foreach_vertex_garbaging_on([](const ref_vertex& ref_v) {
436  ref_v->foreach_edge_garbaging_on([](const ref_edge&) {});
437  });
438  }
439 
440 
441 
442  };
443 
444 
445  template<typename VERTEX_VALUE,
446  typename EDGE_VALUE>
447  class graph : public graph_<VERTEX_VALUE, EDGE_VALUE> {
448 
449  public:
450 
451  // I use this since I have ADL issues....
452  std::function<void (std::ostream&, const VERTEX_VALUE&)> vertex_to_stream;
453  std::function<void (std::ostream&, const EDGE_VALUE&)> edge_to_stream;
454  std::function<void (std::istream&, VERTEX_VALUE&)> vertex_from_stream;
455  std::function<void (std::istream&, EDGE_VALUE&)> edge_from_stream;
456 
457  graph() = default;
458  graph(const graph&) = delete;
459  graph& operator=(const graph&) = delete;
460 
465  typename graph_<VERTEX_VALUE, EDGE_VALUE>::ref_edge connect(const typename graph_<VERTEX_VALUE, EDGE_VALUE>::ref_vertex& v1, const typename graph_<VERTEX_VALUE, EDGE_VALUE>::ref_vertex& v2, const typename graph_<VERTEX_VALUE, EDGE_VALUE>::edge_value_type& v) {
466  auto res = typename graph_<VERTEX_VALUE, EDGE_VALUE>::ref_edge(new typename graph_<VERTEX_VALUE, EDGE_VALUE>::edge_type(v1, v2, v)); // no std::make_shared since constructor is private.
467  v1->E.push_back(res);
468  v2->E.push_back(res);
469  this->E.push_back(res);
470  return res;
471  }
472 
477  typename graph_<VERTEX_VALUE, EDGE_VALUE>::ref_edge connect(const typename graph_<VERTEX_VALUE, EDGE_VALUE>::ref_vertex& v1, const typename graph_<VERTEX_VALUE, EDGE_VALUE>::ref_vertex& v2) {
478  auto res = typename graph_<VERTEX_VALUE, EDGE_VALUE>::ref_edge(new typename graph_<VERTEX_VALUE, EDGE_VALUE>::edge_type(v1, v2, typename graph_<VERTEX_VALUE, EDGE_VALUE>::edge_value_type())); // no std::make_shared since constructor is private.
479  v1->E.push_back(res);
480  v2->E.push_back(res);
481  this->E.push_back(res);
482  return res;
483  }
484 
488  void write(std::ostream& os) {
489  std::map<typename graph_<VERTEX_VALUE, EDGE_VALUE>::ref_vertex, unsigned int> vertex_idf;
490  unsigned int idf = 0;
491 
492  os << this->nb_vertices() << std::endl;
493  this->foreach_vertex([&idf, &vertex_idf, &os, this](auto& ref_v){
494  vertex_idf[ref_v] = idf++;
495  vertex_to_stream(os, (*ref_v)());
496  os << std::endl;
497  });
498 
499  os << this->nb_edges() << std::endl;
500  this->foreach_edge([&vertex_idf, &os, this](auto& ref_e){
501  auto extr_pair = ref_e->extremities();
502  os << vertex_idf[extr_pair.first] << ' ' << vertex_idf[extr_pair.second] << std::endl;
503  edge_to_stream(os, (*ref_e)());
504  os << std::endl;
505  });
506  }
507 
508 
512  void read(std::istream& is) {
513  this->foreach_vertex([](auto ref_v){ref_v->kill();});
514  this->foreach_edge ([](auto ref_e){ref_e->kill();});
515 
516  unsigned int nb;
517  char c;
518  typename graph_<VERTEX_VALUE, EDGE_VALUE>::vertex_value_type v {};
519  typename graph_<VERTEX_VALUE, EDGE_VALUE>::edge_value_type e {};
520 
521  is >> nb; is.get(c);
522  std::vector<typename graph_<VERTEX_VALUE, EDGE_VALUE>::ref_vertex> vtx(nb);
523  for(auto& ref_v : vtx) {
524  vertex_from_stream(is, v);
525  is.get(c);
526  ref_v = ((*this) += v);
527  }
528 
529  is >> nb; is.get(c);
530  for(unsigned int i=0; i < nb; ++i) {
531  unsigned int v1, v2;
532  is >> v1 >> v2; is.get(c);
533  edge_from_stream(is, e);
534  is.get(c);
535 
536  this->connect(vtx[v1], vtx[v2], e);
537  }
538  }
539  };
540 
541  template<typename VERTEX_VALUE>
542  class graph<VERTEX_VALUE, void> : public graph_<VERTEX_VALUE, void> {
543 
544  private:
545 
546 
547  // I use this since I have ADL issues....
548  std::function<void (std::ostream&, const VERTEX_VALUE&)> vertex_to_stream;
549  std::function<void (std::istream&, VERTEX_VALUE&)> vertex_from_stream;
550 
551  public:
552 
553 
554  graph() = default;
555  graph(const graph&) = delete;
556  graph& operator=(const graph&) = delete;
557 
563  auto res = typename graph_<VERTEX_VALUE, void>::ref_edge(new typename graph_<VERTEX_VALUE, void>::edge_type(v1, v2)); // no std::make_shared since constructor is private.
564  v1->E.push_back(res);
565  v2->E.push_back(res);
566  this->E.push_back(res);
567  return res;
568  }
569 
573  void write(std::ostream& os) {
574  std::map<typename graph_<VERTEX_VALUE, void>::ref_vertex, unsigned int> vertex_idf;
575  unsigned int idf = 0;
576 
577  os << this->nb_vertices() << std::endl;
578  this->foreach_vertex([&idf, &vertex_idf, &os, this](auto& ref_v){
579  vertex_idf[ref_v] = idf++;
580  vertex_to_stream(os, (*ref_v)());
581  os << std::endl;
582  });
583 
584  os << this->nb_edges() << std::endl;
585  this->foreach_edge([&vertex_idf, &os](auto& ref_e){
586  auto extr_pair = ref_e->extremities();
587  os << vertex_idf[extr_pair.first] << ' ' << vertex_idf[extr_pair.second] << std::endl;
588  });
589  }
590 
591 
595  void read(std::istream& is) {
596  this->foreach_vertex([](auto ref_v){ref_v->kill();});
597  this->foreach_edge ([](auto ref_e){ref_e->kill();});
598 
599  unsigned int nb;
600  char c;
602 
603  is >> nb; is.get(c);
604  std::vector<typename graph_<VERTEX_VALUE, void>::ref_vertex> vtx(nb);
605  for(auto& ref_v : vtx) {
606  vertex_from_stream(is, v);
607  is.get(c);
608  ref_v = ((*this) += v);
609  }
610 
611  is >> nb; is.get(c);
612  for(unsigned int i=0; i < nb; ++i) {
613  unsigned int v1, v2;
614  is >> v1 >> v2; is.get(c);
615  this->connect(vtx[v1], vtx[v2]);
616  }
617  }
618  };
619 
620 
621  template<typename VERTEX_VALUE, typename EDGE_VALUE>
622  std::ostream& operator<<(std::ostream& os, graph<VERTEX_VALUE, EDGE_VALUE>& g) {
623  g.write(os);
624  return os;
625  }
626 
627  template<typename VERTEX_VALUE, typename EDGE_VALUE>
628  std::istream& operator>>(std::istream& is, graph<VERTEX_VALUE, EDGE_VALUE>& g) {
629  g.read(is);
630  return is;
631  }
632 }
vq3::graph::read
void read(std::istream &is)
Definition: vq3Graph.hpp:512
vq3::vertex
Definition: vq3Graph.hpp:54
vq3::graph::connect
graph_< VERTEX_VALUE, EDGE_VALUE >::ref_edge connect(const typename graph_< VERTEX_VALUE, EDGE_VALUE >::ref_vertex &v1, const typename graph_< VERTEX_VALUE, EDGE_VALUE >::ref_vertex &v2, const typename graph_< VERTEX_VALUE, EDGE_VALUE >::edge_value_type &v)
Definition: vq3Graph.hpp:465
vq3::graph_
Definition: vq3Graph.hpp:53
vq3::graph< VERTEX_VALUE, void >::read
void read(std::istream &is)
Definition: vq3Graph.hpp:595
vq3::graph::write
void write(std::ostream &os)
Definition: vq3Graph.hpp:488
vq3::valued_graph_element
Definition: vq3Graph.hpp:85
vq3::graph_::garbaging_force
void garbaging_force()
Definition: vq3Graph.hpp:429
vq3::edge
Definition: vq3Graph.hpp:55
vq3::graph_::garbaging_unlock
void garbaging_unlock()
Definition: vq3Graph.hpp:414
vq3::graph_::nb_vertices
unsigned int nb_vertices()
Definition: vq3Graph.hpp:324
vq3::graph_::nb_edges
unsigned int nb_edges()
Definition: vq3Graph.hpp:333
vq3::graph::connect
graph_< VERTEX_VALUE, EDGE_VALUE >::ref_edge connect(const typename graph_< VERTEX_VALUE, EDGE_VALUE >::ref_vertex &v1, const typename graph_< VERTEX_VALUE, EDGE_VALUE >::ref_vertex &v2)
Definition: vq3Graph.hpp:477
vq3::graph_::get_edge
ref_edge get_edge(const ref_vertex &v1, const ref_vertex &v2) const
Definition: vq3Graph.hpp:359
vq3::graph_::operator+=
ref_vertex operator+=(const vertex_value_type &v)
Definition: vq3Graph.hpp:349
vq3::graph_element
Definition: vq3Graph.hpp:58
vq3::graph_element::kill
void kill()
Definition: vq3Graph.hpp:76
vq3::graph_::garbaging_lock
void garbaging_lock()
Definition: vq3Graph.hpp:402
vq3::graph_::heap
std::vector< ref_vertex > heap
Definition: vq3Graph.hpp:315
vq3::graph< VERTEX_VALUE, void >::connect
graph_< VERTEX_VALUE, void >::ref_edge connect(const typename graph_< VERTEX_VALUE, void >::ref_vertex &v1, const typename graph_< VERTEX_VALUE, void >::ref_vertex &v2)
Definition: vq3Graph.hpp:562
vq3::graph_element::is_killed
bool is_killed()
Definition: vq3Graph.hpp:81
vq3::graph< VERTEX_VALUE, void >::write
void write(std::ostream &os)
Definition: vq3Graph.hpp:573
vq3::graph
Definition: vq3Graph.hpp:52