1 // -*-mode:c++; c-style:k&r; c-basic-offset:4;-*-
2 //
3 // Copyright 2010, Julian Catchen <jcatchen@uoregon.edu>
4 //
5 // This file is part of Stacks.
6 //
7 // Stacks is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation, either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // Stacks is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with Stacks. If not, see <http://www.gnu.org/licenses/>.
19 //
20
21 //
22 // cmb.cc -- routines to implement the Combination generating class: CombSet.
23 //
24 // Julian Catchen
25 // jcatchen@uoregon.edu
26 // University of Oregon
27 //
28 // $Id: cmb.cc 1990 2010-11-03 04:49:22Z catchen $
29 //
30 #include "cmb.h"
31
32 using namespace mst;
33
34 //
35 // A cache to store combinations generated as (N choose k)
36 // for all set sizes encountered
37 //
38 map<int, map<int, int **> > _cmbs;
39
~CombSet()40 CombSet::~CombSet() {
41 int num_sets, set, i;
42 Cmb **c;
43
44 num_sets = this->compound_comb.size();
45
46 for (set = 0; set < num_sets; set++) {
47 c = this->compound_comb[set];
48 this->destroy(c);
49 }
50
51 //
52 // Delete edge map
53 //
54 for (i = 0; i < (int) this->node_list.size(); i++)
55 delete [] this->edges[i];
56 delete [] this->edges;
57 }
58
CombSet(int n,int k,MinSpanTree * tree)59 CombSet::CombSet(int n, int k, MinSpanTree *tree) {
60 this->max_set_size = n >= k ? k : n;
61 this->num_elements = n - 1;
62 this->index = 0;
63 this->mst = tree;
64
65 int set_size = this->max_set_size - 1;
66 int size;
67 int **comb;
68
69 cerr << " Generating combinations for a set of " << n << " elements, with a maximum subset size of " << k << "\n";
70
71 //
72 // Add the initial combination: the empty set
73 //
74 if (_cmbs.count(this->num_elements) == 0 &&
75 _cmbs[this->num_elements].count(0) == 0) {
76 //cerr << " N: " << this->num_elements << "; K: 0; Total elements: 0\n";
77 comb = new int * [2];
78 comb[0] = new int[1];
79 comb[0][0] = -1;
80 comb[1] = NULL;
81 _cmbs[this->num_elements][0] = comb;
82 }
83
84 while (set_size > 0) {
85 //
86 // Check if this set of combinations is already cached.
87 //
88 if (_cmbs.count(this->num_elements) > 0 &&
89 _cmbs[this->num_elements].count(set_size) > 0) {
90 set_size--;
91 continue;
92 }
93
94 //
95 // How many combinations will we make?
96 //
97 size = (int) this->num_combinations(this->num_elements, set_size);
98
99 cerr << " N: " << this->num_elements << "; K: " << set_size << "; Total elements: " << size << "\n";
100
101 //
102 // Generate all combinations, N choose K; N=num_elements, K=set_size
103 //
104 comb = this->generate_combinations(this->num_elements, set_size, size);
105
106 //
107 // Cache this set of combinations
108 //
109 _cmbs[this->num_elements][set_size] = comb;
110
111 set_size--;
112 }
113
114 this->catalog_tree();
115
116 //
117 // Finally, generate all combinations of nodes in the tree.
118 //
119 int max = this->max_set_size < this->num_elements ? this->max_set_size : this->num_elements + 1;
120 for (set_size = 0; set_size < max; set_size++)
121 this->partition_tree(set_size);
122
123 cerr << " Total compound combinations for sets of size " << n << ": " << this->compound_comb.size() << "\n";
124 }
125
catalog_tree()126 int CombSet::catalog_tree() {
127 set<int> visited;
128 queue<Node *> q;
129 uint i, n_1, n_2;
130
131 //
132 // Create a two-dimensional array to represent edges between nodes in the tree
133 //
134 uint cnt = this->mst->node_count();
135 //cerr << "Creating a two-dimensional array of size: " << cnt << " x " << cnt << "\n";
136 this->edges = new int * [cnt];
137 for (i = 0; i < cnt; i++)
138 this->edges[i] = new int[cnt];
139
140 Node *n = this->mst->head();
141 q.push(n);
142 cnt = 0;
143
144 while (!q.empty()) {
145 n = q.front();
146 q.pop();
147 visited.insert(n->id);
148
149 this->node_list.push_back(n);
150 this->node_map[n->id] = cnt;
151 cnt++;
152
153 for (i = 0; i < n->min_adj_list.size(); i++)
154 if (visited.count(n->min_adj_list[i]->id) == false)
155 q.push(n->min_adj_list[i]);
156 }
157
158 n = this->mst->head();
159 q.push(n);
160 visited.clear();
161
162 while (!q.empty()) {
163 n = q.front();
164 q.pop();
165 visited.insert(n->id);
166
167 for (i = 0; i < n->min_adj_list.size(); i++) {
168
169 if (visited.count(n->min_adj_list[i]->id) == false) {
170 n_1 = this->node_map[n->id];
171 n_2 = this->node_map[n->min_adj_list[i]->id];
172
173 // Create a list of min spanning edges
174 this->edge_list.push_back(make_pair(n->id, n->min_adj_list[i]->id));
175 // Mark the nodes as connected in our edge array
176 this->edges[n_1][n_2] = 1;
177 this->edges[n_2][n_1] = 1;
178 // Queue this node to be visited next
179 q.push(n->min_adj_list[i]);
180 }
181 }
182 }
183
184 return 0;
185 }
186
partition_tree(uint set_size)187 int CombSet::partition_tree(uint set_size) {
188 uint i, j;
189 set<int> visited;
190 queue<Node *> q;
191 Node *n;
192 int n_1, n_2, node_cnt, cmb_cnt;
193 Cmb **new_comb, *cmb;
194 list<Node *> nlist_work;
195
196 int **comb = _cmbs[this->num_elements][set_size];
197 int *subgraph = new int[this->node_list.size()];
198
199 //
200 // We want to methodically remove every set of branches of set_size size. The
201 // subgraphs represent the combinations we want to generate.
202 //
203 for (i = 0; comb[i] != NULL; ++i) {
204 //
205 // This compound combination will consist of set_size+1 subgraphs
206 //
207 new_comb = new Cmb * [set_size + 2];
208 new_comb[set_size + 1] = NULL;
209
210 //
211 // Initialize working node list.
212 //
213 nlist_work = this->node_list;
214
215 //
216 // Remove edges
217 //
218 for (j = 0; j < set_size; j++) {
219 n_1 = this->edge_list[comb[i][j]].first;
220 n_2 = this->edge_list[comb[i][j]].second;
221 this->edges[this->node_map[n_1]][this->node_map[n_2]] = 0;
222 this->edges[this->node_map[n_2]][this->node_map[n_1]] = 0;
223 }
224
225 //
226 // Traverse the subgraphs of the tree and record combinations.
227 //
228 visited.clear();
229 cmb_cnt = 0;
230 while (nlist_work.size() > 0) {
231 node_cnt = 0;
232 n = nlist_work.front();
233 q.push(n);
234 nlist_work.pop_front();
235 //subgraph[node_cnt] = n->id;
236
237 while (!q.empty()) {
238 n = q.front();
239 q.pop();
240 visited.insert(n->id);
241
242 subgraph[node_cnt] = n->id;
243 node_cnt++;
244 nlist_work.remove(n);
245
246 for (j = 0; j < n->min_adj_list.size(); j++) {
247 n_1 = this->node_map[n->id];
248 n_2 = this->node_map[n->min_adj_list[j]->id];
249
250 if (visited.count(n->min_adj_list[j]->id) == false &&
251 edges[n_1][n_2] == 1) {
252 q.push(n->min_adj_list[j]);
253 }
254 }
255 }
256
257 //
258 // Package up this combination.
259 //
260 cmb = new Cmb;
261 cmb->size = node_cnt;
262 cmb->elem = new int[cmb->size];
263 for (j = 0; j < cmb->size; j++)
264 cmb->elem[j] = subgraph[j];
265 new_comb[cmb_cnt] = cmb;
266 cmb_cnt++;
267 }
268
269 this->compound_comb.push_back(new_comb);
270
271 //
272 // Reset the edges.
273 //
274 for (j = 0; j < set_size; j++) {
275 n_1 = this->edge_list[comb[i][j]].first;
276 n_2 = this->edge_list[comb[i][j]].second;
277 this->edges[this->node_map[n_1]][this->node_map[n_2]] = 1;
278 this->edges[this->node_map[n_2]][this->node_map[n_1]] = 1;
279 }
280 }
281
282 delete [] subgraph;
283
284 return 0;
285 }
286
generate_combinations(int n,int k,int total)287 int **CombSet::generate_combinations(int n, int k, int total) {
288 int **comb;
289
290 //
291 // Generate an int pointer for each combination, terminate the list with
292 // a NULL pointer.
293 //
294 comb = new int * [total + 1];
295 for (int i = 0; i < total; i++)
296 comb[i] = new int[k];
297 comb[total] = NULL;
298
299 //
300 // Setup the initial combination
301 //
302 int comb_num = 0;
303
304 for (int i = 0; i < k; i++)
305 comb[comb_num][i] = i;
306 comb_num++;
307
308 //
309 // Generate each successive combination
310 //
311 while (comb_num < total) {
312 for (int i = 0; i < k; i++)
313 comb[comb_num][i] = comb[comb_num - 1][i];
314 this->next_combination(comb[comb_num], n, k);
315 comb_num++;
316 }
317
318 return comb;
319 }
320
next_combination(int * comb,int n,int k)321 int CombSet::next_combination(int *comb, int n, int k) {
322 int i;
323
324 //
325 // The zero'th position has been incremented to its maximal value,
326 // it's not possible to further increment values in the set.
327 //
328 if (comb[0] > n - k)
329 return 0;
330
331 //
332 // Increment the last position in the set.
333 //
334 i = k - 1;
335 comb[i]++;
336
337 //
338 // Check if the last position has reached its maximal possible value,
339 // if so, move back one position, and increment it.
340 //
341 while ((i > 0) && (comb[i] >= n - k + 1 + i)) {
342 i--;
343 comb[i]++;
344 }
345
346 //
347 // Move from the position we incremented above back out to the final position
348 //
349 for (i = i + 1; i < k; i++)
350 comb[i] = comb[i - 1] + 1;
351
352 return 1;
353 }
354
num_combinations(int n,int k)355 long int CombSet::num_combinations(int n, int k) {
356 //
357 // Compute the binomial coefficient using the method of:
358 // Y. Manolopoulos, "Binomial coefficient computation: recursion or iteration?",
359 // ACM SIGCSE Bulletin, 34(4):65-67, 2002.
360 //
361 long int r = 1;
362 long int s = (k < n - k) ? n - k + 1 : k + 1;
363
364 for (long int i = n; i >= s; i--)
365 r = r * i / (n - i + 1);
366
367 return r;
368 }
369
370 //
371 // Return a variable length array of Cmb objects, terminated by a NULL pointer.
372 //
next(int map[])373 Cmb **CombSet::next(int map[]) {
374
375 if (this->index >= (int) this->compound_comb.size())
376 return NULL;
377
378 // int index, i, j, k, n;
379 // int size = this->compound_comb[this->index]->size;
380 // int *e = this->compound_comb[this->index]->elem;
381
382 // Cmb **c = new Cmb * [size + 1];
383
384 // for (i = 0; i < size; i++) {
385 // index = e[i];
386 // // sets vector index number
387 // k = this->compound_set[index].first;
388 // // combination number
389 // n = this->compound_set[index].second;
390
391 // c[i] = new Cmb;
392 // c[i]->size = this->size[k];
393 // c[i]->elem = new int[this->size[k]];
394
395 // for (j = 0; j < this->size[k]; j++)
396 // c[i]->elem[j] = (map == NULL) ?
397 // this->sets[k][n][j] :
398 // map[this->sets[k][n][j]];
399 // }
400
401 // c[size] = NULL;
402
403 Cmb **c = this->compound_comb[this->index];
404
405 this->index++;
406
407 return c;
408 }
409
reset()410 void CombSet::reset() {
411 this->index = 0;
412 }
413
destroy(Cmb ** cmb)414 void CombSet::destroy(Cmb **cmb) {
415
416 for (uint j = 0; cmb[j] != NULL; j++) {
417 delete [] cmb[j]->elem;
418 delete cmb[j];
419 }
420 delete [] cmb;
421 }
422
write_cmb(int * comb,int size)423 void write_cmb(int *comb, int size) {
424 stringstream s;
425 string t;
426
427 s << "{";
428
429 for (int i = 0; i < size; i++)
430 s << comb[i] << ", ";
431 t = s.str().substr(0, s.str().length() - 2);
432 t += "}";
433
434 cerr << t << "\n";
435 }
436