PaGMO  1.1.5
topology/base.cpp
1 /*****************************************************************************
2  * Copyright (C) 2004-2015 The PaGMO development team, *
3  * Advanced Concepts Team (ACT), European Space Agency (ESA) *
4  * *
5  * https://github.com/esa/pagmo *
6  * *
7  * act@esa.int *
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  * This program is distributed in the hope that it will be useful, *
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17  * GNU General Public License for more details. *
18  * *
19  * You should have received a copy of the GNU General Public License *
20  * along with this program; if not, write to the *
21  * Free Software Foundation, Inc., *
22  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
23  *****************************************************************************/
24 
25 #include <algorithm>
26 #include <boost/graph/adjacency_list.hpp>
27 #include <boost/graph/johnson_all_pairs_shortest.hpp>
28 #include <boost/numeric/conversion/cast.hpp>
29 #include <iostream>
30 #include <iterator>
31 #include <sstream>
32 #include <string>
33 #include <typeinfo>
34 #include <utility>
35 #include <vector>
36 
37 #include "../exceptions.h"
38 #include "base.h"
39 
40 namespace pagmo { namespace topology {
41 
43 
46 base::base():m_graph() {}
48 
53 base::base(const base &t):m_graph(t.m_graph) {}
54 
56 
64 {
65  if (this != &t) {
66  m_graph = t.m_graph;
67  }
68  return *this;
69 }
70 
72 
76 
79 
81 
86 std::string base::get_name() const
87 {
88  return typeid(*this).name();
89 }
90 
92 
100 std::string base::human_readable_terse() const
101 {
102  std::ostringstream s;
103  s << "Topology type: " << get_name() << '\n';
104  s << "\tNumber of vertices: " << get_number_of_vertices() << '\n';
105  s << "\tNumber of edges: " << get_number_of_edges() << '\n';
106  s << human_readable_extra() << '\n';
107  return s.str();
108 }
109 
111 
118 std::string base::human_readable() const
119 {
120  std::ostringstream s;
121  s << human_readable_terse();
122  s << "Connections:\n\n";
123  std::pair<v_iterator,v_iterator> vertices = get_vertices();
124  std::pair<a_iterator,a_iterator> adj_vertices;
125  for (; vertices.first != vertices.second; ++vertices.first) {
126  adj_vertices = get_adjacent_vertices(*vertices.first);
127  s << (*vertices.first);
128  if (adj_vertices.first != adj_vertices.second) {
129  s << " -> {";
130  while (adj_vertices.first != adj_vertices.second) {
131  s << (*adj_vertices.first);
132  ++adj_vertices.first;
133  if (adj_vertices.first != adj_vertices.second) {
134  s << ' ';
135  }
136  }
137  s << '}';
138  }
139  s << '\n';
140  }
141  return s.str();
142 }
143 
145 
151 std::string base::human_readable_extra() const
152 {
153  return std::string();
154 }
155 
157 
159 
163 {
164  boost::add_vertex(m_graph);
165 }
166 
167 // Check that a vertex number does not overflow the number of vertices in the graph.
168 void base::check_vertex_index(const vertices_size_type &idx) const
169 {
170  if (idx >= num_vertices(m_graph)) {
171  pagmo_throw(value_error,"invalid vertex index");
172  }
173 }
174 
176 
183 std::pair<base::a_iterator,base::a_iterator> base::get_adjacent_vertices(const vertices_size_type &idx) const
184 {
185  check_vertex_index(idx);
186  return boost::adjacent_vertices(boost::vertex(idx,m_graph),m_graph);
187 }
188 
190 
197 std::vector<base::vertices_size_type> base::get_v_adjacent_vertices(const vertices_size_type &idx) const
198 {
199  const std::pair<base::a_iterator,base::a_iterator> tmp = get_adjacent_vertices(idx);
200  return std::vector<base::vertices_size_type>(tmp.first,tmp.second);
201 }
202 
204 
213 {
214  check_vertex_index(n);
215  check_vertex_index(m);
216  // Find n's adjacent vertices.
217  const std::pair<a_iterator,a_iterator> a_vertices = boost::adjacent_vertices(boost::vertex(n,m_graph),m_graph);
218  return std::find(a_vertices.first,a_vertices.second,boost::vertex(m,m_graph)) != a_vertices.second;
219 }
220 
222 
230 {
231  const std::pair<base::a_iterator,base::a_iterator> v = get_adjacent_vertices(idx);
232  return boost::numeric_cast<edges_size_type>(std::distance(v.first,v.second));
233 }
234 
236 
245 {
246  check_vertex_index(n);
247  check_vertex_index(m);
248  // Find n's inversely adjacent vertices.
249  const std::pair<ia_iterator,ia_iterator> ia_vertices = boost::inv_adjacent_vertices(boost::vertex(n,m_graph),m_graph);
250  return std::find(ia_vertices.first,ia_vertices.second,boost::vertex(m,m_graph)) != ia_vertices.second;
251 }
252 
254 
261 std::pair<base::ia_iterator,base::ia_iterator> base::get_inv_adjacent_vertices(const vertices_size_type &idx) const
262 {
263  check_vertex_index(idx);
264  return boost::inv_adjacent_vertices(boost::vertex(idx,m_graph),m_graph);
265 }
266 
268 
275 std::vector<base::vertices_size_type> base::get_v_inv_adjacent_vertices(const vertices_size_type &idx) const
276 {
277  const std::pair<base::ia_iterator,base::ia_iterator> tmp = get_inv_adjacent_vertices(idx);
278  return std::vector<base::vertices_size_type>(tmp.first,tmp.second);
279 }
280 
282 
286 {
287  const std::pair<base::ia_iterator,base::ia_iterator> v = get_inv_adjacent_vertices(idx);
288  return boost::numeric_cast<edges_size_type>(std::distance(v.first,v.second));
289 }
290 
292 
299 {
300  if (are_adjacent(n,m)) {
301  pagmo_throw(value_error,"cannot add edge, vertices are already connected");
302  }
303  const std::pair<e_descriptor,bool> result = boost::add_edge(boost::vertex(n,m_graph),boost::vertex(m,m_graph),m_graph);
304  pagmo_assert(result.second);
305  set_weight(result.first, 1.0);
306 }
307 
309 
315 void base::set_weight(const base::e_descriptor &e, double w) {
316  if (w < 0.0 || w > 1.0) {
317  pagmo_throw(value_error,"invalid migration probability");
318  }
319  m_graph[e].migr_probability = w;
320 }
321 
323 
329 double base::get_weight(const base::e_descriptor &e) const {
330  return m_graph[e].migr_probability;
331 }
332 
334 
339 void base::set_weight(double w) {
340  std::pair<e_iterator, e_iterator> es = boost::edges(m_graph);
341  for(; es.first != es.second; ++es.first) {
342  set_weight(*es.first, w);
343  }
344 }
345 
347 
353 void base::set_weight(const vertices_size_type &n, double w) {
354  std::pair<a_iterator,a_iterator> adj_vertices = boost::adjacent_vertices(boost::vertex(n, m_graph), m_graph);
355  for(; adj_vertices.first != adj_vertices.second; ++adj_vertices.first) {
356  const std::pair<e_descriptor, bool> e = boost::edge(boost::vertex(n, m_graph), *adj_vertices.first, m_graph);
357  set_weight(e.first, w);
358  }
359 }
360 
362 
369 void base::set_weight(const vertices_size_type &n, const vertices_size_type &m, double w)
370 {
371  if (!are_adjacent(n, m)) {
372  pagmo_throw(value_error,"cannot set edge weight, vertices are not connected");
373  }
374  const std::pair<e_descriptor, bool> e = boost::edge(n, m, m_graph);
375  set_weight(e.first, w);
376 }
377 
379 
387 {
388  if (!are_adjacent(n, m)) {
389  pagmo_throw(value_error,"cannot get edge weight, vertices are not connected");
390  }
391  const std::pair<e_descriptor, bool> e = boost::edge(n, m, m_graph);
392  return get_weight(e.first);
393 }
394 
396 
403 {
404  if (!are_adjacent(n,m)) {
405  pagmo_throw(value_error,"cannot remove edge, vertices are not connected");
406  }
407  boost::remove_edge(boost::vertex(n,m_graph),boost::vertex(m,m_graph),m_graph);
408 }
409 
411 
415 {
416  for (std::pair<v_iterator,v_iterator> vertices = get_vertices(); vertices.first != vertices.second; ++vertices.first) {
417  boost::clear_vertex(*vertices.first,m_graph);
418  }
419 }
420 
422 
427 std::pair<base::v_iterator,base::v_iterator> base::get_vertices() const
428 {
429  return boost::vertices(m_graph);
430 }
431 
433 
437 {
438  return boost::num_vertices(m_graph);
439 }
440 
442 
446 {
447  return boost::num_edges(m_graph);
448 }
449 
451 
463 {
464  std::map<e_descriptor, int> map;
465  boost::associative_property_map<std::map<e_descriptor, int> > map2(map);
466  std::pair<e_iterator, e_iterator> es = boost::edges(m_graph);
467  for(; es.first != es.second; ++es.first) {
468  map2[(*es.first)] = 1;
469  }
470 
471  // Output matrix.
472  std::vector<std::vector<int> > D(boost::numeric_cast<std::vector<std::vector<int> >::size_type>(get_number_of_vertices()),
473  std::vector<int>(boost::numeric_cast<std::vector<int>::size_type>(get_number_of_vertices())));
474  boost::johnson_all_pairs_shortest_paths(m_graph, D, weight_map(map2));
475  double retval = 0;
476  for (std::vector<std::vector<int> >::size_type i = 0; i < D.size(); ++i) {
477  for (std::vector<int>::size_type j = 0; j < D[i].size(); ++j) {
478  retval += D[i][j];
479  }
480  }
481  if (get_number_of_vertices() < 2) {
482  return 0;
483  } else {
484  return retval / (static_cast<double>(get_number_of_vertices()) * (get_number_of_vertices() - 1));
485  }
486 }
487 
490 {
491  // Output value.
492  double cc = 0.0;
493  // Get the vertices.
494  std::pair<v_iterator, v_iterator> vertices;
495  std::vector<base::vertices_size_type> adj_vertices;
496  vertices = get_vertices();
497  // Loop through vertices and calculate individual clustering coeffient.
498  for(; vertices.first != vertices.second; vertices.first++) {
499  adj_vertices = get_v_adjacent_vertices(*vertices.first);
500  if(adj_vertices.size() > 1) {
501  // Count the number of nodes in adj_vertices that are adjacent to one another.
502  for(unsigned int i = 0; i < adj_vertices.size()-1; i++) {
503  for(unsigned int j = i; j < adj_vertices.size(); j++) {
504  if(i != j && are_adjacent(adj_vertices[i],adj_vertices[j])) {
505  cc += 2.0/(adj_vertices.size() * (adj_vertices.size() - 1));
506  }
507  }
508  }
509  // Now get the clustering coefficient of the node by dividing by...
510  //c /= adj_vertices.size() * (adj_vertices.size() - 1);
511  } else {
512  // In the case that a node only has one neighbour
513  // the node has a clustering coefficient of 1.
514  cc += 1.0;
515  }
516  // Update the network clustering coefficient
517  //cc += c;
518  }
519  // Average clustering coefficient
520  cc /= get_number_of_vertices();
521  // Output
522  return cc;
523 }
524 
526 std::vector<double> base::get_degree_distribution() const
527 {
528  // First, find the maximum degree of any node and define the output vector
529  std::pair<v_iterator, v_iterator> vertices;
530  int mx = 0;
531  vertices = get_vertices();
532  double ne = (get_number_of_edges());
533  ne = 1/ne;
534  for(; vertices.first != vertices.second; vertices.first++) {
535  if((int)get_num_adjacent_vertices(*vertices.first) > mx) mx = (int)get_num_adjacent_vertices(*vertices.first);
536  }
537  std::vector<double> deg_dist(mx+1);
538  for(int i = 0; i < mx; i++) deg_dist[i] = 0;
539  // Loop through each vertex and increment deg_dist accordingly
540  vertices = get_vertices();
541  for(; vertices.first != vertices.second; vertices.first++) {
542  deg_dist[get_num_adjacent_vertices(*vertices.first)]+=ne;
543 
544  }
545 // // Return the degree distribution vector
546  return deg_dist;
547 }
548 
550 
555 {
556  add_vertex();
558 }
559 
561 
569 std::ostream &operator<<(std::ostream &s, const base &t)
570 {
571  s << t.human_readable();
572  return s;
573 }
574 
575 }}
Root PaGMO namespace.
bool are_inv_adjacent(const vertices_size_type &, const vertices_size_type &) const
Return true if two vertices are inversely adjacent.
void add_vertex()
Add a vertex.
virtual ~base()
Trivial destructor.
Base topology class.
Definition: topology/base.h:75
std::vector< vertices_size_type > get_v_adjacent_vertices(const vertices_size_type &) const
Return vector of adjacent vertices.
graph_type::edges_size_type edges_size_type
Edges size type.
double get_clustering_coefficient() const
Calculate clustering coefficient.
double get_average_shortest_path_length() const
Calculate average path length.
void remove_edge(const vertices_size_type &, const vertices_size_type &)
Remove an edge.
edges_size_type get_num_inv_adjacent_vertices(const vertices_size_type &) const
Return the number of inversely adjacent vertices.
std::string human_readable() const
Return complete human readable representation.
std::string human_readable_terse() const
Return terse human readable representation.
vertices_size_type get_number_of_vertices() const
Get number of vertices.
std::vector< vertices_size_type > get_v_inv_adjacent_vertices(const vertices_size_type &) const
Return vector of inversely adjacent vertices.
graph_type::vertices_size_type vertices_size_type
Vertices size type.
edges_size_type get_num_adjacent_vertices(const vertices_size_type &) const
Return the number of adjacent vertices.
base & operator=(const base &)
Assignment operator.
boost::graph_traits< graph_type >::edge_descriptor e_descriptor
Edge descriptor.
std::vector< double > get_degree_distribution() const
Constructs the Degree Distribution.
virtual std::string human_readable_extra() const
Return extra information for human readable representation.
double get_weight(const vertices_size_type &, const vertices_size_type &) const
Get the migration probability.
void remove_all_edges()
Remove all edges.
base()
Default constructor.
std::pair< ia_iterator, ia_iterator > get_inv_adjacent_vertices(const vertices_size_type &) const
Return iterator range to inversely adjacent vertices.
std::ostream & operator<<(std::ostream &s, const base &t)
Overload stream insertion operator for topology::base.
void add_edge(const vertices_size_type &, const vertices_size_type &)
Add an edge.
edges_size_type get_number_of_edges() const
Get number of edges.
virtual void connect(const vertices_size_type &idx)=0
Establish connections between islands during a push_back() operation.
void push_back()
Push back vertex.
void set_weight(double)
Sets the migration probability.
std::pair< a_iterator, a_iterator > get_adjacent_vertices(const vertices_size_type &) const
Return iterator range to adjacent vertices.
virtual std::string get_name() const
Get name of the topology.
std::pair< v_iterator, v_iterator > get_vertices() const
Return iterator range to vertices.
bool are_adjacent(const vertices_size_type &, const vertices_size_type &) const
Return true if two vertices are adjacent.