comparison src/find_connected.c @ 1:7eab80f86779 draft

add FLOCK
author immport-devteam
date Mon, 27 Feb 2017 13:26:09 -0500
parents
children
comparison
equal deleted inserted replaced
0:8d951baf795f 1:7eab80f86779
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <assert.h>
5
6 //static const char *rcsid = "$Id: find_connected.c,v 1.1 2008/09/05 21:54:40 rpl Exp $";
7
8 int find_connected(int **G, int num_dense_grids, int ndim, int *grid_clusterID);
9 void depth_first(int startnode);
10
11 void bail(const char *); /* exits via abort */
12 static void check_clusters(int *gcID, int ndense);
13 static void merge_cluster(int from, int into);
14
15
16 /* Vars that will not change througout the depth-first recursion. We
17 store them here to avoid endless replication on the stack. */
18 static int **Gr=0;
19 static int *gcID = 0; /* grid cluster IDs */
20 static int *cluster_count=0; /* count of nodes per cluster */
21 static int ndense=0;
22 static int ndim=0;
23 /* cid changes between depth-first searches, but is constant within a
24 single search, so it goes here. */
25 static int cid=0;
26
27 /* Find connected components in the graph of neighboring grids defined in G.
28 *
29 * Output:
30 *
31 * grid_clusterID[] -- cluster to which each dense grid was assigned
32 * return value -- number of clusters assigned.
33 */
34 int find_connected(int **G, int n_dense_grids, int num_dm, int *grid_clusterID)
35 {
36 int nclust=0; /* number of clusters found */
37 int i;
38 int *subfac;
39 int subval=0,nempty=0;
40 int clustid=0;
41
42 size_t sz = n_dense_grids*sizeof(int);
43 cluster_count = malloc(sz);
44 if(!cluster_count)
45 bail("find_connected: Unable to allocate %zd bytes.\n");
46 memset(cluster_count,0,sz);
47
48 /* set up the statics that will be used in the DFS */
49 Gr=G;
50 gcID = grid_clusterID;
51 ndense = n_dense_grids;
52 ndim = num_dm;
53
54
55 for(i=0;i<ndense;++i)
56 grid_clusterID[i] = -1;
57
58 for(i=0;i<ndense;++i) {
59 if(grid_clusterID[i] < 0) { /* grid hasn't been assigned yet */
60 cid = nclust++;
61 depth_first(i);
62 }
63 }
64
65 #ifndef NDEBUG
66 check_clusters(gcID,ndense);
67 #endif
68
69 /* At this point we probably have some clusters that are empty due to merging.
70 We want to compact the cluster numbering to eliminate the empty clusters. */
71
72 subfac = malloc(sz);
73 if(!subfac)
74 bail("find_connected: Unable to allocate %zd bytes.\n");
75 subval=0;
76 nempty=0;
77
78 /* cluster #i needs to have its ID decremented by 1 for each empty cluster with
79 ID < i. Precaclulate the decrements in this loop: */
80 for(i=0;i<nclust;++i) {
81 //clustid = grid_clusterID[i];
82 if(cluster_count[i] == 0) {
83 subval++;
84 nempty++;
85 }
86 subfac[i] = subval;
87 }
88
89 /* Now apply the decrements to all of the dense grids */
90 for(i=0;i<ndense;++i) {
91 clustid = grid_clusterID[i];
92 grid_clusterID[i] -= subfac[clustid];
93 }
94
95 #ifndef NDEBUG
96 // check_clusters(gcID,ndense);
97 #endif
98
99 /* correct the number of clusters found */
100 nclust -= nempty;
101
102 return nclust;
103 }
104
105
106 /* Do a depth-first search for a single connected component in graph
107 * G. Start from node, tag the nodes found with cid, and record
108 * the tags in grid_clusterID. Also, record the node count in
109 * cluster_count. If we find a node that has already been assigned to
110 * a cluster, that means we're merging two clusters, so zero out the
111 * old cid's node count.
112 *
113 * Note that our graph is constructed as a DAG, so we can be
114 * guaranteed to terminate without checking for cycles.
115 *
116 * Note2: this function can potentially recurse to depth = ndense.
117 * Plan stack size accordingly.
118 *
119 * Output:
120 *
121 * grid_clusterID[] -- array where we tag the nodes.
122 * cluster_count[] -- count of the number of nodes per cluster.
123 */
124
125 void depth_first(int node)
126 {
127 int i;
128
129 if(gcID[node] == cid) // we're guaranteed no cycles, but it is possible to reach a node
130 return; // through two different paths in the same cluster. This early
131 // return saves us some unneeded work.
132
133 /* Check to see if we are merging a cluster */
134 if(gcID[node] >= 0) {
135 /* We are, so zero the count for the old cluster. */
136 cluster_count[ gcID[node] ] = 0;
137 merge_cluster(gcID[node], cid);
138 return;
139 }
140
141 /* Update for this node */
142 gcID[node] = cid;
143 cluster_count[cid]++;
144
145 /* Recursively search the child nodes */
146 for(i=0; i<ndim; ++i)
147 if(Gr[node][i] >= 0) /* This is a child node */
148 depth_first(Gr[node][i]);
149 }
150
151 void bail(const char *msg)
152 {
153 fprintf(stderr,"%s",msg);
154 abort();
155 }
156
157
158 static void check_clusters(int *gcID, int ndense)
159 {
160 int i;
161
162 for(i=0; i<ndense; ++i)
163 if(gcID[i] < 0) {
164 fprintf(stderr,"faulty cluster id at i= %d\n",i);
165 abort();
166 }
167 }
168
169 static void merge_cluster(int from, int into)
170 {
171 int i;
172
173 for(i=0; i<ndense; ++i)
174 if(gcID[i] == from)
175 gcID[i] = into;
176 }