Visualisierung2
FastCommunity.cpp
Go to the documentation of this file.
1 #include "FastCommunity.h"
2 // Based on the implementation of http://www.cs.unm.edu/~aaron/research/fastmodularity.htm
3 // by Aaron Clauset
4 
5 
6 using namespace std;
7 
8 
10 {
11 }
12 
13 
15 {
16 }
17 
19 {
20  readInputFile(path);
21 
22  int cutstep = gparm.maxid; // step at which to record aglomerated network
23  //int cutstep = 1;
24  // ----------------------------------------------------------------------
25  // Allocate data structures for main loop
26  a = new double [gparm.maxid];
27  Q = new double [gparm.n+1];
28  joins = new apair [gparm.n+1];
29  for (int i=0; i<gparm.maxid; i++) { a[i] = 0.0; }
30  for (int i=0; i<gparm.n+1; i++) { Q[i] = 0.0; joins[i].x = 0; joins[i].y = 0; }
31  int t = 1;
32  Qmax.y = -4294967296.0; Qmax.x = 0;
33  if (cutstep > 0) { groupListsSetup(); } // will need to track agglomerations
34 
35  cout << "now building initial dQ[]" << endl;
36  buildDeltaQMatrix(); // builds dQ[] and h
37  // ----------------------------------------------------------------------
38  // Start FastCommunity algorithm
39  cout << "starting algorithm now." << endl;
40  mytuple dQmax;
41  int isupport, jsupport;
42  while (h->heapSize() > 1) {
43 
44  // ---------------------------------
45  // Find largest dQ
46  dQmax = h->popMaximum(); // select maximum dQ_ij // convention: insert i into j
47  if (dQmax.m < -4000000000.0) { break; } // no more joins possible
48  //cout << "Q["<<t-1<<"] = "<<Q[t-1];
49 
50  // ---------------------------------
51  // Merge the chosen communities
52  //cout << "\tdQ = " << dQmax.m << "\t |H| = " << h->heapSize() << "\n";
53  if (dq[dQmax.i].v == nullptr || dq[dQmax.j].v == nullptr) {
54  cout << dQmax.i<<endl;
55  cout << dQmax.j<<endl;
56  cout << "WARNING: invalid join (" << dQmax.i << " " << dQmax.j << ") found at top of heap\n"; cin >> pauseme;
57  }
58  isupport = dq[dQmax.i].v->returnNodecount();
59  jsupport = dq[dQmax.j].v->returnNodecount();
60  if (isupport < jsupport) {
61  //cout << " join: " << dQmax.i << " -> " << dQmax.j << "\t";
62  //cout << "(" << isupport << " -> " << jsupport << ")\n";
63  mergeCommunities(dQmax.i, dQmax.j); // merge community i into community j
64  joins[t].x = dQmax.i; // record merge of i(x) into j(y)
65  joins[t].y = dQmax.j; //
66  } else { //
67  //cout << " join: " << dQmax.i << " <- " << dQmax.j << "\t";
68  //cout << "(" << isupport << " <- " << jsupport << ")\n";
69  dq[dQmax.i].heap_ptr = dq[dQmax.j].heap_ptr; // take community j's heap pointer
70  dq[dQmax.i].heap_ptr->i = dQmax.i; // mark it as i's
71  dq[dQmax.i].heap_ptr->j = dQmax.j; // mark it as i's
72  mergeCommunities(dQmax.j, dQmax.i); // merge community j into community i
73  joins[t].x = dQmax.j; // record merge of j(x) into i(y)
74  joins[t].y = dQmax.i; //
75  } //
76  Q[t] = dQmax.m + Q[t-1]; // record Q(t)
77 
78  // ---------------------------------
79  // Note that it is the .joins file which contains both the dendrogram and the corresponding
80  // Q values. The file format is tab-delimited columns of data, where the columns are:
81  // 1. the community which grows
82  // 2. the community which was absorbed
83  // 3. the modularity value Q after the join
84  // 4. the time step value
85 
86  // ---------------------------------
87  // If cutstep valid, then do some work
88  if (t <= cutstep) { groupListsUpdate(joins[t].x, joins[t].y); }
89  //if (t == cutstep) { recordNetwork(); recordGroupLists(); groupListsStats(); }
90 
91  if (Q[t] > Qmax.y) { Qmax.y = Q[t]; Qmax.x = t; }
92 
93  t++; // increment time
94  } // ------------- end community merging loop
95  cout << "exited safely" << endl;
96 
97  int index = getClusterIndex();
98  return c[index].members;
99 }
100 
101 
102 // ------------------------------------------------------------------------------------
103 
104 void FastCommunity::readInputFile(std::string path)
105 {
106 
107  // temporary variables for this function
108  int numnodes = 0;
109  int numlinks = 0;
110  int s,f,t;
111  myEdge **last;
112  myEdge *newedge;
113  myEdge *current; // pointer for checking edge existence
114  bool existsFlag; // flag for edge existence
115 
116  // First scan through the input file to discover the largest node id. We need to
117  // do this so that we can allocate a properly sized array for the sparse matrix
118  // representation.
119  cout << " scanning input file for basic information." << endl;
120  cout << " edgecount: [0]"<<endl;
121  ifstream fscan(path.c_str(), ios::in);
122  while (fscan >> s >> f) { // read friendship pair (s,f)
123  numlinks++; // count number of edges
124  if (f < s) { t = s; s = f; f = t; } // guarantee s < f
125  if (f > numnodes) { numnodes = f; } // track largest node index
126  edgeList.push_back(s-1);
127  edgeList.push_back(f-1);
128  }
129  fscan.close();
130  cout << " edgecount: ["<<numlinks<<"] total (first pass)"<<endl;
131  gparm.maxid = numnodes+2; // store maximum index
132  elist = new myEdge [2*numlinks]; // create requisite number of edges
133  int ecounter = 0; // index of next edge of elist to be used
134 
135  // Now that we know numnodes, we can allocate the space for the sparse matrix, and
136  // then reparse the file, adding edges as necessary.
137  cout << " allocating space for network." << endl;
138  e = new myEdge [gparm.maxid]; // (unordered) sparse adjacency matrix
139  last = new myEdge* [gparm.maxid]; // list of pointers to the last edge in each row
140  numnodes = 0; // numnodes now counts number of actual used node ids
141  numlinks = 0; // numlinks now counts number of bi-directional edges created
142 
143  cout << " reparsing the input file to build network data structure." << endl;
144  cout << " edgecount: [0]"<<endl;
145  ifstream fin(path.c_str(), ios::in);
146  while (fin >> s >> f) {
147  s++; f++; // increment s,f to prevent using e[0]
148  if (f < s) { t = s; s = f; f = t; } // guarantee s < f
149  numlinks++; // increment link count (preemptive)
150  if (e[s].so == 0) { // if first edge with s, add s and (s,f)
151  e[s].so = s; //
152  e[s].si = f; //
153  last[s] = &e[s]; // point last[s] at self
154  numnodes++; // increment node count
155  } else { // try to add (s,f) to s-edgelist
156  current = &e[s]; //
157  existsFlag = false; //
158  while (current != nullptr) { // check if (s,f) already in edgelist
159  if (current->si==f) { //
160  existsFlag = true; // link already exists
161  numlinks--; // adjust link-count downward
162  break; //
163  } //
164  current = current->next; // look at next edge
165  } //
166  if (!existsFlag) { // if not already exists, append it
167  newedge = &elist[ecounter++]; // grab next-free-edge
168  newedge -> so = s; //
169  newedge -> si = f; //
170  last[s] -> next = newedge; // append newedge to [s]'s list
171  last[s] = newedge; // point last[s] to newedge
172  } //
173  } //
174 
175  if (e[f].so == 0) { // if first edge with f, add f and (f,s)
176  e[f].so = f; //
177  e[f].si = s; //
178  last[f] = &e[f]; // point last[s] at self
179  numnodes++; // increment node count
180  } else { // try to add (f,s) to f-edgelist
181  if (!existsFlag) { // if (s,f) wasn't in s-edgelist, then
182  newedge = &elist[ecounter++]; // (f,s) not in f-edgelist
183  newedge -> so = f; //
184  newedge -> si = s; //
185  last[f] -> next = newedge; // append newedge to [f]'s list
186  last[f] = newedge; // point last[f] to newedge
187  } //
188  }
189  }
190  cout << " edgecount: ["<<numlinks<<"] total (second pass)"<<endl;
191  fin.close();
192 
193  gparm.m = numlinks; // store actual number of edges created
194  gparm.n = numnodes; // store actual number of nodes used
195  return;
196 }
197 
199 {
200 
201  // Given that we've now populated a sparse (unordered) adjacency matrix e (e),
202  // we now need to construct the intial dQ matrix according to the definition of dQ
203  // which may be derived from the definition of modularity Q:
204  // Q(t) = \sum_{i} (e_{ii} - a_{i}^2) = Tr(e) - ||e^2||
205  // thus dQ is
206  // dQ_{i,j} = 2* ( e_{i,j} - a_{i}a_{j} )
207  // where a_{i} = \sum_{j} e_{i,j} (i.e., the sum over the ith row)
208  // To create dQ, we must insert each value of dQ_{i,j} into a binary search tree,
209  // for the jth column. That is, dQ is simply an array of such binary search trees,
210  // each of which represents the dQ_{x,j} adjacency vector. Having created dQ as
211  // such, we may happily delete the matrix e in order to free up more memory.
212  // The next step is to create a max-heap data structure, which contains the entries
213  // of the following form (value, s, t), where the heap-key is 'value'. Accessing the
214  // root of the heap gives us the next dQ value, and the indices (s,t) of the vectors
215  // in dQ which need to be updated as a result of the merge.
216 
217 
218  // First we compute e_{i,j}, and the compute+store the a_{i} values. These will be used
219  // shortly when we compute each dQ_{i,j}.
220  myEdge *current;
221  double eij = (double)(0.5/gparm.m); // intially each e_{i,j} = 1/m
222  for (int i=1; i<gparm.maxid; i++) { // for each row
223  a[i] = 0.0; //
224  if (e[i].so != 0) { // ensure it exists
225  current = &e[i]; // grab first edge
226  a[i] = eij; // initialize a[i]
227  while (current->next != nullptr) { // loop through remaining edges
228  a[i] += eij; // add another eij
229  current = current->next; //
230  }
231  Q[0] += -1.0*a[i]*a[i]; // calculate initial value of Q
232  }
233  }
234 
235  // now we create an empty (ordered) sparse matrix dq[]
236  dq = new nodenub [gparm.maxid]; // initialize dq matrix
237  for (int i=0; i<gparm.maxid; i++) { //
238  dq[i].heap_ptr = nullptr; // no pointer in the heap at first
239  if (e[i].so != 0) { dq[i].v = new myVector(2+(int)floor(gparm.m*a[i])); }
240  else { dq[i].v = nullptr; }
241  }
242  h = new myMaxheap(gparm.n); // allocate max-heap of size = number of nodes
243 
244  // Now we do all the work, which happens as we compute and insert each dQ_{i,j} into
245  // the corresponding (ordered) sparse vector dq[i]. While computing each dQ for a
246  // row i, we track the maximum dQmax of the row and its (row,col) indices (i,j). Upon
247  // finishing all dQ's for a row, we insert the tuple into the max-heap hQmax. That
248  // insertion returns the itemaddress, which we then store in the nodenub heap_ptr for
249  // that row's vector.
250  double dQ;
251  mytuple dQmax; // for heaping the row maxes
252 
253  for (int i=1; i<gparm.maxid; i++) {
254  if (e[i].so != 0) {
255  current = &e[i]; // grab first edge
256  dQ = 2.0*(eij-(a[current->so]*a[current->si])); // compute its dQ
257  dQmax.m = dQ; // assume it is maximum so far
258  dQmax.i = current->so; // store its (row,col)
259  dQmax.j = current->si; //
260  dq[i].v->insertItem(current->si, dQ); // insert its dQ
261  while (current->next != nullptr) { //
262  current = current->next; // step to next edge
263  dQ = 2.0*(eij-(a[current->so]*a[current->si])); // compute new dQ
264  if (dQ > dQmax.m) { // if dQ larger than current max
265  dQmax.m = dQ; // replace it as maximum so far
266  dQmax.j = current->si; // and store its (col)
267  }
268  dq[i].v->insertItem(current->si, dQ); // insert it into vector[i]
269  }
270  dq[i].heap_ptr = h->insertItem(dQmax); // store the pointer to its loc in heap
271  }
272  }
273 
274  delete [] elist; // free-up adjacency matrix memory in two shots
275  delete [] e; //
276  return;
277 }
279 
280  myList *newList;
281  c = new myStub [gparm.maxid];
282  for (int i=0; i<gparm.maxid; i++) {
283  if (e[i].so != 0) { // note: internal indexing
284  newList = new myList; // create new community member
285  newList->index = i; // with index i
286  c[i].members = newList; // point ith community at newList
287  c[i].size = 1; // point ith community at newList
288  c[i].last = newList; // point last[] at that element too
289  c[i].valid = true; // mark as valid community
290  }
291  }
292 
293 }
294 
295 // ------------------------------------------------------------------------------------
296 
298 
299  // To do the join operation for a pair of communities (i,j), we must update the dQ
300  // values which correspond to any neighbor of either i or j to reflect the change.
301  // In doing this, there are three update rules (cases) to follow:
302  // 1. jix-triangle, in which the community x is a neighbor of both i and j
303  // 2. jix-chain, in which community x is a neighbor of i but not j
304  // 3. ijx-chain, in which community x is a neighbor of j but not i
305  //
306  // For the first two cases, we may make these updates by simply getting a list of
307  // the elements (x,dQ) of [i] and stepping through them. If x==j, then we can ignore
308  // that value since it corresponds to an edge which is being absorbed by the joined
309  // community (i,j). If [j] also contains an element (x,dQ), then we have a triangle;
310  // if it does not, then we have a jix-chain.
311  //
312  // The last case requires that we step through the elements (x,dQ) of [j] and update each
313  // if [i] does not have an element (x,dQ), since that implies a ijx-chain.
314  //
315  // Let d([i]) be the degree of the vector [i], and let k = d([i]) + d([j]). The running
316  // time of this operation is O(k log k)
317  //
318  // Essentially, we do most of the following operations for each element of
319  // dq[i]_x where x \not= j
320  // 1. add dq[i]_x to dq[j]_x (2 cases)
321  // 2. remove dq[x]_i
322  // 3. update maxheap[x]
323  // 4. add dq[i]_x to dq[x]_j (2 cases)
324  // 5. remove dq[j]_i
325  // 6. update maxheap[j]
326  // 7. update a[j] and a[i]
327  // 8. delete dq[i]
328 
329  myDpair *list, *current, *temp;
330  mytuple newMax;
331  int t = 1;
332 
333  // -- Working with the community being inserted (dq[i])
334  // The first thing we must do is get a list of the elements (x,dQ) in dq[i]. With this
335  // list, we can then insert each into dq[j].
336 
337  list = dq[i].v->returnTreeAsList(); // get a list of items in dq[i].v
338  current = list; // store ptr to head of list
339 
340  // ---------------------------------------------------------------------------------
341  // SEARCHING FOR JIX-TRIANGLES AND JIX-CHAINS --------------------------------------
342  // Now that we have a list of the elements of [i], we can step through them to check if
343  // they correspond to an jix-triangle, a jix-chain, or the edge (i,j), and do the appropriate
344  // operation depending.
345 
346  while (current!=nullptr) { // insert list elements appropriately
347 
348  // If the element (x,dQ) is actually (j,dQ), then we can ignore it, since it will
349  // correspond to an edge internal to the joined community (i,j) after the join.
350  if (current->x != j) {
351 
352  // Now we must decide if we have a jix-triangle or a jix-chain by asking if
353  // [j] contains some element (x,dQ). If the following conditional is TRUE,
354  // then we have a jix-triangle, ELSE it is a jix-chain.
355 
356  if (dq[j].v->findItem(current->x)) {
357  // CASE OF JIX-TRIANGLE
358 
359  // We first add (x,dQ) from [i] to [x] as (j,dQ), since [x] essentially now has
360  // two connections to the joined community [j].
361 
362  dq[current->x].v->insertItem(j,current->y); // (step 1)
363 
364  // Then we need to delete the element (i,dQ) in [x], since [i] is now a
365  // part of [j] and [x] must reflect this connectivity.
366  dq[current->x].v->deleteItem(i); // (step 2)
367 
368  // After deleting an item, the tree may now have a new maximum element in [x],
369  // so we need to check it against the old maximum element. If it's new, then
370  // we need to update that value in the heap and reheapify.
371  newMax = dq[current->x].v->returnMaxStored(); // (step 3)
372  h->updateItem(dq[current->x].heap_ptr, newMax);
373 
374  // Finally, we must insert (x,dQ) into [j] to note that [j] essentially now
375  // has two connections with its neighbor [x].
376  dq[j].v->insertItem(current->x,current->y); // (step 4)
377 
378  } else {
379  // CASE OF JIX-CHAIN
380 
381  // The first thing we need to do is calculate the adjustment factor (+) for updating elements.
382  double axaj = -2.0*a[current->x]*a[j];
383  // Then we insert a new element (j,dQ+) of [x] to represent that [x] has
384  // acquired a connection to [j], which was [x]'d old connection to [i]
385  dq[current->x].v->insertItem(j,current->y + axaj); // (step 1)
386 
387  // Now the deletion of the connection from [x] to [i], since [i] is now
388  // a part of [j]
389  dq[current->x].v->deleteItem(i); // (step 2)
390 
391  // Deleting that element may have changed the maximum element for [x], so we
392  // need to check if the maximum of [x] is new (checking it against the value
393  // in the heap) and then update the maximum in the heap if necessary.
394  newMax = dq[current->x].v->returnMaxStored(); // (step 3)
395  h->updateItem(dq[current->x].heap_ptr, newMax);
396 
397  // Finally, we insert a new element (x,dQ+) of [j] to represent [j]'s new
398  // connection to [x]
399  dq[j].v->insertItem(current->x,current->y + axaj); // (step 4)
400  }
401  }
402 
403  temp = current;
404  current = current->next; // move to next element
405  delete temp;
406  temp = nullptr;
407  t++;
408  }
409 
410  // We've now finished going through all of [i]'s connections, so we need to delete the element
411  // of [j] which represented the connection to [i]
412  dq[j].v->deleteItem(i); // (step 5)
413 
414  // We can be fairly certain that the maximum element of [j] was also the maximum
415  // element of [i], so we need to check to update the maximum value of [j] that
416  // is in the heap.
417  newMax = dq[j].v->returnMaxStored(); // (step 6)
418  h->updateItem(dq[j].heap_ptr, newMax);
419 
420  // ---------------------------------------------------------------------------------
421  // SEARCHING FOR IJX-CHAINS --------------------------------------------------------
422  // So far, we've treated all of [i]'s previous connections, and updated the elements
423  // of dQ[] which corresponded to neighbors of [i] (which may also have been neighbors
424  // of [j]. Now we need to update the neighbors of [j] (as necessary)
425 
426  // Again, the first thing we do is get a list of the elements of [j], so that we may
427  // step through them and determine if that element constitutes an ijx-chain which
428  // would require some action on our part.
429  list = dq[j].v->returnTreeAsList(); // get a list of items in dq[j].v
430  current = list; // store ptr to head of list
431  t = 1;
432 
433  while (current != nullptr) { // insert list elements appropriately
434 
435  // If the element (x,dQ) of [j] is not also (i,dQ) (which it shouldn't be since we've
436  // already deleted it previously in this function), and [i] does not also have an
437  // element (x,dQ), then we have an ijx-chain.
438  if ((current->x != i) && (!dq[i].v->findItem(current->x))) {
439  // CASE OF IJX-CHAIN
440 
441  // First we must calculate the adjustment factor (+).
442  double axai = -2.0*a[current->x]*a[i];
443  // Now we must add an element (j,+) to [x], since [x] has essentially now acquired
444  // a new connection to [i] (via [j] absorbing [i]).
445  dq[current->x].v->insertItem(j, axai); // (step 1)
446 
447  // This new item may have changed the maximum dQ of [x], so we must update it.
448  newMax = dq[current->x].v->returnMaxStored(); // (step 3)
449  h->updateItem(dq[current->x].heap_ptr, newMax);
450 
451  // And we must add an element (x,+) to [j], since [j] as acquired a new connection
452  // to [x] (via absorbing [i]).
453  dq[j].v->insertItem(current->x, axai); // (step 4)
454  newMax = dq[j].v->returnMaxStored(); // (step 6)
455 
456  h->updateItem(dq[j].heap_ptr, newMax);
457 
458  }
459 
460  temp = current;
461  current = current->next; // move to next element
462  delete temp;
463  temp = nullptr;
464  t++;
465  }
466 
467  // Now that we've updated the connections values for all of [i]'s and [j]'s neighbors,
468  // we need to update the a[] vector to reflect the change in fractions of edges after
469  // the join operation.
470  a[j] += a[i]; // (step 7)
471  a[i] = 0.0;
472 
473  // ---------------------------------------------------------------------------------
474  // Finally, now we need to clean up by deleting the vector [i] since we'll never
475  // need it again, and it'll conserve memory. For safety, we also set the pointers
476  // to be nullptr to prevent inadvertent access to the deleted data later on.
477 
478  delete dq[i].v; // (step 8)
479  dq[i].v = nullptr; // (step 8)
480  dq[i].heap_ptr = nullptr; //
481 
482  return;
483 
484 }
485 
486 // ------------------------------------------------------------------------------------
487 
488 // ------------------------------------------------------------------------------------
489 
490 void FastCommunity::groupListsUpdate(const int x, const int y) {
491 
492  c[y].last->next = c[x].members; // attach c[y] to end of c[x]
493  c[y].last = c[x].last; // update last[] for community y
494  c[y].size += c[x].size; // add size of x to size of y
495 
496  c[x].members = nullptr; // delete community[x]
497  c[x].valid = false; //
498  c[x].size = 0; //
499  c[x].last = nullptr; // delete last[] for community x
500 
501  return;
502 }
503 
504 // ------------------------------------------------------------------------------------
505 // ------------------------------------------------------------------------------------
506 // records the agglomerated list of indices for each valid community
507 
509 {
510  myList *current;
511  int last_i;
512  for (int i=0; i<gparm.maxid; i++) {
513  if (c[i].valid) {
514  //std::cout << "GROUP[ "<<i-1<<" ][ "<<c[i].size<<" ]"<<std::endl; // external format
515  current = c[i].members;
516  last_i = i;
517  /*while (current != nullptr) {
518  std::cout << current->index-1 << std::endl; // external format
519  current = current->next;
520  }*/
521  }
522  }
523  return last_i;
524 }
525 
526 // ------------------------------------------------------------------------------------
527 
529 
530  myDpair *list, *current, *temp;
531 
532  for (int i=0; i<gparm.maxid; i++) {
533  if (dq[i].heap_ptr != nullptr) {
534  list = dq[i].v->returnTreeAsList(); // get a list of items in dq[i].v
535  current = list; // store ptr to head of list
536  while (current != nullptr) {
537  // source target weight (external representation)
538  cout << i-1 << "\t" << current->x-1 << "\t" << current->y << endl;
539 
540  temp = current; // clean up memory and move to next
541  current = current->next;
542  delete temp;
543  }
544  }
545  }
546 
547  return;
548 }
549 // ------------------------------------------------------------------------------------
550 // function for computing statistics on the list of groups
551 
553 
554  gstats.numgroups = 0;
555  gstats.maxsize = 0;
556  gstats.minsize = gparm.maxid;
557  double count = 0.0;
558  for (int i=0; i<gparm.maxid; i++) {
559  if (c[i].valid) {
560  gstats.numgroups++; // count number of communities
561  count += 1.0;
562  if (c[i].size > gstats.maxsize) { gstats.maxsize = c[i].size; } // find biggest community
563  if (c[i].size < gstats.minsize) { gstats.minsize = c[i].size; } // find smallest community
564  // compute mean group size
565  gstats.meansize = (double)(c[i].size)/count + (((double)(count-1.0)/count)*gstats.meansize);
566  }
567  }
568 
569  count = 0.0;
570  gstats.sizehist = new double [gstats.maxsize+1];
571  for (int i=0; i<gstats.maxsize+1; i++) { gstats.sizehist[i] = 0; }
572  for (int i=0; i<gparm.maxid; i++) {
573  if (c[i].valid) {
574  gstats.sizehist[c[i].size] += 1.0; // tabulate histogram of sizes
575  count += 1.0;
576  }
577  }
578 
579  for (int i=0; i<gstats.maxsize+1; i++) { gstats.sizehist[i] = gstats.sizehist[i]/count; }
580 
581  return;
582 }
583 
584 // ------------------------------------------------------------------------------------
myEdge * next
Pointer zur naechsten Kante.
Definition: myEdge.h:9
void buildDeltaQMatrix()
Erzeugt die Matrix fuer die Moadalitaeten.
int index
Listenindex.
Definition: myList.h:7
void readInputFile(std::string path)
Liest den Graphen aud der angegeben Datei.
mytuple * heap_ptr
Adresse des Knoten im MaxHeap.
Definition: FastCommunity.h:37
int getClusterIndex()
Im Projekt wird, dadurch, dass eine Tiefensuche verwirklicht werden soll, alle Cluster verschmolzen b...
void groupListsUpdate(const int x, const int y)
Updatet die Clusterliste, indem die Clusterliste von x in die Clusterliste von y eingegliedert wird...
myDpair * next
Pointer auf naechstes Datenpaar.
Definition: myDpair.h:9
Definition: myList.h:4
Definition: myEdge.h:4
void recordNetwork()
Gibt die Eigenschaften des Graphen aus.
void mergeCommunities(int i, int j)
Verschmilzt zwei Cluster mit Index i und j zu einem.
void groupListsStats()
Bestimmt die Eigenschaften der Cluster.
int si
Index des Kantenendes.
Definition: myEdge.h:8
void groupListsSetup()
Erzeugt und initialisiert eine Clasterliste.
double y
Beschreibt den Wert/Parameter an der Stelle x.
Definition: myDpair.h:8
Definition: myDpair.h:4
int i
Zeilenindex des Elements.
Definition: myElement.h:9
myList * clusterAndOrder(std::string path)
Die Hauptmethode dieser Klasse. Sie liest den Graphen aus der Datei, clustert ihn, fuehrt die Tiefensuche durch und gibt die Reihenfolge der Knoten als Liste zurueck.
double m
Abgelegter Wert/Parameter.
Definition: myElement.h:8
int x
Beschreibt einen Key oder einen Index.
Definition: myDpair.h:7
int j
Spaltenindex des Elements.
Definition: myElement.h:10
int x
Der hinzufuegende Knoten.
Definition: FastCommunity.h:48
Definition: myStub.h:6
int so
Index des Kantenursprungs.
Definition: myEdge.h:7