1 /*
2  * cTopology.h
3  * Avida
4  *
5  * Copyright 2005-2011 Michigan State University. All rights reserved.
6  *
7  *
8  *  This file is part of Avida.
9  *
10  *  Avida is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
11  *  as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
12  *
13  *  Avida is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public License along with Avida.
17  *  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #ifndef cTopology_h
22 #define cTopology_h
23 
24 /*! Builds different topologies out of ranges of cells.
25 
26 This file contains templated algorithms that create a particular cell
27 topology out of a given range of cells.  In every case, the range of cells is
28 specified by a begin/end iterator pair.
29 */
30 
31 #include "AvidaTools.h"
32 
33 using namespace AvidaTools;
34 
35 /*! Builds a torus topology out of the cells betwen the iterators.
36 In a torus, each cell is connected to up to 8 neighbors (including diagonals),
37 and connections DO wrap around the logical edges of the torus.
38 */
39 template< typename InputIterator >
build_torus(InputIterator begin,InputIterator end,unsigned int x_size,unsigned int y_size)40 void build_torus(InputIterator begin, InputIterator end, unsigned int x_size, unsigned int y_size) {
41   // Get the offset from the start of this range.  This is used to modify the
42   // parameters and return for GridNeighbor.
43   int offset = begin->GetID();
44 
45   for(InputIterator i=begin; i!=end; ++i) {
46     // The majority of all connections.
47     i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, -1, -1)]);
48     i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, 0, -1)]);
49     i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, 1, -1)]);
50     i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, 1, 0)]);
51     i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, 1, 1)]);
52     i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, 0, 1)]);
53     i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, -1, 1)]);
54     i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, -1, 0)]);
55   }
56 }
57 
58 
59 /*! Builds a grid topology out of the cells betwen the iterators.
60 In a grid, each cell is connected to up to 8 neighbors (including diagonals),
61 and connections do NOT wrap around the logical edges of the grid.
62 */
63 template< typename InputIterator >
build_grid(InputIterator begin,InputIterator end,unsigned int x_size,unsigned int y_size)64 void build_grid(InputIterator begin, InputIterator end, unsigned int x_size, unsigned int y_size) {
65   // Start with a torus.
66   build_torus(begin, end, x_size, y_size);
67   int offset = begin->GetID();
68 
69   // And now remove the connections that wrap around.
70   for(InputIterator i=begin; i!=end; ++i) {
71     int id = i->GetID();
72     unsigned int x = (id-offset) % x_size;
73     unsigned int y = (id-offset) / x_size;
74 
75     if(x==0) {
76       i->ConnectionList().Remove(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, -1, -1)]);
77       i->ConnectionList().Remove(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, -1, 0)]);
78       i->ConnectionList().Remove(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, -1, 1)]);
79     }
80     if(x==(x_size-1)) {
81       i->ConnectionList().Remove(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, 1, -1)]);
82       i->ConnectionList().Remove(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, 1, 0)]);
83       i->ConnectionList().Remove(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, 1, 1)]);
84     }
85     if(y==0) {
86       i->ConnectionList().Remove(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, -1, -1)]);
87       i->ConnectionList().Remove(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, 0, -1)]);
88       i->ConnectionList().Remove(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, 1, -1)]);
89     }
90     if(y==(y_size-1)) {
91       i->ConnectionList().Remove(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, -1, 1)]);
92       i->ConnectionList().Remove(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, 0, 1)]);
93       i->ConnectionList().Remove(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, 1, 1)]);
94     }
95   }
96 }
97 
98 
99 /*! Builds a clique topology out of the cells betwen the iterators.
100 In a clique, each cell is connected to all other cells in the given range.
101 */
102 template< typename InputIterator >
build_clique(InputIterator begin,InputIterator end,unsigned int x_size,unsigned int y_size)103 void build_clique(InputIterator begin, InputIterator end, unsigned int x_size, unsigned int y_size) {
104   for(InputIterator i=begin; i!=end; ++i) {
105     for(InputIterator j=begin; j!=end; ++j) {
106       if(j!=i) {
107         i->ConnectionList().Push(j);
108       }
109     }
110   }
111 }
112 
113 
114 /*! Builds a hexagonal grid topology out of the cells between the iterators.  In
115 a hex grid, each cell has at most 6 neighbors, and connections do not wrap around
116 edges.
117 */
118 template< typename InputIterator >
build_hex(InputIterator begin,InputIterator end,unsigned int x_size,unsigned int y_size)119 void build_hex(InputIterator begin, InputIterator end, unsigned int x_size, unsigned int y_size) {
120   // Start with a grid:
121   build_grid(begin, end, x_size, y_size);
122   int offset = begin->GetID();
123   // ... and remove connections to the NE,SW:
124   for(InputIterator i=begin; i!=end; ++i) {
125     i->ConnectionList().Remove(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, 1, -1)]);
126     i->ConnectionList().Remove(&begin[GridNeighbor(i->GetID()-offset, x_size, y_size, -1, 1)]);
127   }
128 }
129 
130 /*! Builds a 3-dimensional lattice of cells, where the dimensions of the lattice are specified by
131  x, y, and z.
132 
133  A cell in the middle of the lattice is connected to 26 other cells (9 above, 9 below, and 8 on the
134  same plane).  Edges do not wrap around in any direction.
135 */
136 template< typename InputIterator >
build_lattice(InputIterator begin,InputIterator end,unsigned int x_size,unsigned int y_size,unsigned int z_size)137 void build_lattice(InputIterator begin, InputIterator end,
138 		   unsigned int x_size, unsigned int y_size, unsigned int z_size) {
139   // First we're going to create z grids each sized x by y:
140   unsigned int gridsize = x_size * y_size;
141 
142   for (unsigned int i=0; i<z_size; ++i) {
143     build_grid(&begin[gridsize*i], &begin[gridsize*(i+1)], x_size, y_size);
144   }
145 
146   // This is the offset from the beginning of the cell_array; req'd to support demes.
147   int offset = begin->GetID();
148 
149   // Now, iterate through each cell, and link them to their neighbors above and below:
150   for (InputIterator i=begin; i!=end; ++i) {
151     unsigned int layer = (i->GetID()-offset) / gridsize;
152     unsigned int x = (i->GetID()-offset) % x_size;
153     unsigned int y = (i->GetID()-offset) / x_size;
154 
155     // The below is a big mess.  The reason it's a mess is because we have to respect the boundaries
156     // of the grid.  There are probably much cleaner ways to do this, but it's complicated
157     // enough now without having to think that through.  And anyway, this is only run
158     // at initialization.  Feel free to fix it, however.
159     if (layer != 0) {
160       // We're not at the bottom; link to the layer below us.
161       if (x != 0) {
162 	if (y != 0) {
163 	  i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset-gridsize, x_size, y_size, -1, -1)]);
164 	}
165 	if (y != (y_size-1)) {
166 	  i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset-gridsize, x_size, y_size, -1, 1)]);
167 	}
168 	i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset-gridsize, x_size, y_size, -1, 0)]);
169       }
170 
171       if (x != (x_size-1)) {
172 	if (y != 0) {
173 	  i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset-gridsize, x_size, y_size, 1, -1)]);
174 	}
175 	if (y != (y_size-1)) {
176 	  i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset-gridsize, x_size, y_size, 1, 1)]);
177 	}
178 	i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset-gridsize, x_size, y_size, 1, 0)]);
179       }
180 
181       if (y != 0) {
182 	i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset-gridsize, x_size, y_size, 0, -1)]);
183       }
184       if(y != (y_size-1)) {
185 	i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset-gridsize, x_size, y_size, 0, 1)]);
186       }
187 
188       // And now the cell right below this one:
189       i->ConnectionList().Push(&begin[i->GetID()-offset-gridsize]);
190     }
191 
192     if (layer != (z_size-1)) {
193       // We're not at the top; link to the layer above us:
194       if(x != 0) {
195 	if (y != 0) {
196 	  i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset+gridsize, x_size, y_size, -1, -1)]);
197 	}
198 	if(y != (y_size-1)) {
199 	  i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset+gridsize, x_size, y_size, -1, 1)]);
200 	}
201 	i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset+gridsize, x_size, y_size, -1, 0)]);
202       }
203 
204       if (x != (x_size-1)) {
205 	if (y != 0) {
206 	  i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset+gridsize, x_size, y_size, 1, -1)]);
207 	}
208 	if (y != (y_size-1)) {
209 	  i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset+gridsize, x_size, y_size, 1, 1)]);
210 	}
211 	i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset+gridsize, x_size, y_size, 1, 0)]);
212       }
213 
214       if (y != 0) {
215 	i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset+gridsize, x_size, y_size, 0, -1)]);
216       }
217       if(y != (y_size-1)) {
218 	i->ConnectionList().Push(&begin[GridNeighbor(i->GetID()-offset+gridsize, x_size, y_size, 0, 1)]);
219       }
220 
221       // And now the cell right above this one:
222       i->ConnectionList().Push(&begin[i->GetID()-offset+gridsize]);
223     }
224   }
225 }
226 
227 
228 /*
229  Builds a random connected network topology for organisms to communicate through.
230 
231  */
232 template< typename InputIterator >
build_random_connected_network(InputIterator begin,InputIterator end,unsigned int x_size,unsigned int y_size,cRandom & rng)233 void build_random_connected_network(InputIterator begin, InputIterator end, unsigned int x_size, unsigned int y_size, cRandom& rng) {
234 
235 	// keep track of boundaries for this deme:
236 	int offset = begin->GetID();
237 	int demeSize = x_size * y_size;
238 
239 	// keep track of cells that have been connected already:
240 	std::set<int> connected_Cells;
241 
242 	InputIterator i, j, random_Connected_Cell;
243 
244 
245 
246 	for(i = begin; i != end; ++i) {
247 		// select a random cell in this deme to connect to:
248 		int targetCellID;
249 		do {
250 			targetCellID = rng.GetInt(0, demeSize);
251 		} while((targetCellID + offset) == i->GetID());
252 
253 		j = &begin[targetCellID];
254 
255 		// verify no connection exists between i and j:
256 		if(i->ConnectionList().FindPtr(j) == NULL) {
257 			// create bidirectional connections:
258 			i->ConnectionList().Push(j);
259 			j->ConnectionList().Push(i);
260 
261 			// check if either i or j is connected to the
262 			// main graph:
263 			if(connected_Cells.count(i->GetID()) == 0 && connected_Cells.count(j->GetID()) == 0) {
264 				// neither i nor j is connected to the main graph
265 
266 				// check if main network is empty:
267 				if(connected_Cells.empty()) {
268 					connected_Cells.insert(i->GetID());
269 					connected_Cells.insert(j->GetID());
270 				} else {
271 					// pick some random cell that is connected:
272 					int randomIndex = rng.GetInt(0, connected_Cells.size());
273 					int counter = 0;
274 					int idValue = 0;
275 					set<int>::iterator pos;
276 					for(pos = connected_Cells.begin(); pos != connected_Cells.end(); ++pos) {
277 						if(counter == randomIndex) {
278 							idValue = *pos;
279 							break;
280 						} else {
281 							counter++;
282 						}
283 					}
284 
285 					// retrieve the actual cell:
286 					random_Connected_Cell = &begin[idValue-offset];
287 
288 					// randomly select i or j to connect with main network:
289 					int zeroOrOne = rng.GetInt(0,2);
290 
291 					if(zeroOrOne) {
292 						// connect i to main network:
293 						i->ConnectionList().Push(random_Connected_Cell);
294 						random_Connected_Cell->ConnectionList().Push(i);
295 					} else {
296 						// connect j to main network:
297 						j->ConnectionList().Push(random_Connected_Cell);
298 						random_Connected_Cell->ConnectionList().Push(j);
299 					}
300 
301 					// add both cells to the main network:
302 					// don't care about duplicates...
303 					connected_Cells.insert(i->GetID());
304 					connected_Cells.insert(j->GetID());
305 				}
306 
307 			} else {
308 				connected_Cells.insert(i->GetID());
309 				connected_Cells.insert(j->GetID());
310 			}
311 		}
312 	}
313 
314 
315 	// the code above ensures that we have *at the least* a random connected
316 	// bidirectional network.
317 	// sprinkle additional edges between the cells:
318 
319 	// we are going to add random extra edges... note demeSize bound is arbitrary.
320 	int extraEdges = rng.GetInt(0, demeSize);
321 	int a, b;
322 
323 	for(int n = 0; n < extraEdges; ++n) {
324 		// must select two random cells from the network:
325 		a = rng.GetInt(0,demeSize);
326 		b = rng.GetInt(0,demeSize);
327 
328 		while(a == b)
329 			b = rng.GetInt(0,demeSize);
330 
331 		i = &begin[a];
332 		j = &begin[b];
333 
334 		// check for existing connection between the two:
335 		if(i->ConnectionList().FindPtr(j) == NULL) {
336 			i->ConnectionList().Push(j);
337 			j->ConnectionList().Push(i);
338 		}
339 	}
340 }
341 
342 
343 //! Helper function to connect two cells.
344 template <typename InputIterator>
connect(InputIterator u,InputIterator v)345 void connect(InputIterator u, InputIterator v) {
346 	assert(u != v);
347 	u->ConnectionList().Push(v);
348 	v->ConnectionList().Push(u);
349 }
350 
351 //! Helper function to test if two cells are already connected.
352 template <typename InputIterator>
edge(InputIterator u,InputIterator v)353 bool edge(InputIterator u, InputIterator v) {
354 	assert(u != v);
355 	return u->ConnectionList().FindPtr(v) || v->ConnectionList().FindPtr(u);
356 }
357 
358 
359 /*! Builds a scale-free network from the given range of cells.
360 
361  This function is an implementation of the Barab\'asi-Albert "preferential attachment"
362  algorithm for iteratively constructing a scale-free network.
363 
364  If we think of the population as a graph G, where cells are vertices and connections
365  are edges, then |E(G)| is the number of edges in the graph and d(u \in V(G)) is the
366  degree of a vertex in that graph, the algorithm for preferential attachment is defined as:
367 
368  Input:
369  m = number of edges to be added for each new vertex
370  alpha = "power," the degree to which vertices with large numbers of edges are weighted.
371  zero_appeal = offset to prefer vertices with 0 edges
372 
373  Initialization:
374  G = a graph, where all nodes have degree >= 1
375 
376  foreach vertex u to be added to G:
377  foreach vertex v \in G != u, where !e(u,v), and until m edges are added:
378  connect u-v with probability: (d(v)/|E(G)|)^alpha + zero_appeal
379  */
380 template <typename InputIterator>
build_scale_free(InputIterator begin,InputIterator end,int m,double alpha,double zero_appeal,cRandom & rng)381 void build_scale_free(InputIterator begin, InputIterator end, int m, double alpha, double zero_appeal, cRandom& rng) {
382 	assert(begin != end);
383 	assert(&begin[1] != end); // at least two vertices.
384 	// Connect the first and second cells:
385 	connect(&begin[0], &begin[1]);
386 	// And initialize the edge and vertex counts:
387 	int edge_count=1;
388 	int vertex_count=2;
389 
390 	// Now, for each new vertex (that is, vertices 2+):
391 	for(InputIterator u=&begin[2]; u!=end; ++u, ++vertex_count) {
392 		// Figure out how many edges we can add:
393 		int to_add = std::min(vertex_count, m);
394 		int added=0;
395 		// Loop through all the vertices currently in the graph:
396 		InputIterator v=begin;
397 		while(added < to_add) {
398 			// If we haven't already connected u and v:
399 			if(!edge(u, v)) {
400 				// Connect them with P = (d(v)/|E(G)|)^alpha + zero_appeal:
401 				double p_edge = (double)v->ConnectionList().GetSize() / edge_count;
402 				p_edge = pow(p_edge, alpha) + zero_appeal;
403 				// Protect against negative and over-large probabilities:
404 				assert(p_edge >= 0.0);
405 				p_edge = std::min(p_edge, 1.0);
406 				// Probabilistically connect u and v:
407 				if(rng.P(p_edge)) {
408 					connect(u, v);
409 					++edge_count;
410 					++added;
411 				}
412 			}
413 			// Loop back around to the beginning - note that u is the current end, 'cause
414 			// building this graph is an iterative process.
415 			if(++v == u) { v = begin; }
416 		}
417 	}
418 }
419 
420 
421 #endif
422