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