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