|
1 |
| -/* The t is for "Template" C++ file |
| 1 | +/* Implementation of random_reduction_tree template |
2 | 2 | */
|
3 | 3 |
|
4 | 4 | #include "assoc.hxx"
|
5 | 5 | using namespace std;
|
6 | 6 |
|
7 |
| -random_kary_tree::random_kary_tree() { }; |
8 |
| -random_kary_tree::~random_kary_tree() { }; |
| 7 | +random_reduction_tree::random_reduction_tree() { }; |
| 8 | +random_reduction_tree::~random_reduction_tree() { }; |
9 | 9 |
|
10 |
| -random_kary_tree::random_kary_tree(int k, long n, FLOAT_T* A) : k_(k), n_(n), A_(A) |
| 10 | +random_reduction_tree::random_reduction_tree(int k, long n, FLOAT_T* A) |
| 11 | + : k_(k), n_(n), A_(A) |
11 | 12 | {
|
12 | 13 | typename tree<FLOAT_T>::iterator top, root;
|
13 | 14 | top = t.begin();
|
14 | 15 | root = t.insert(top, nan(""));
|
15 |
| - if (k != 2) { |
| 16 | + irem = n-1; /* Inner nodes remaining */ |
| 17 | + lrem = n; /* Leaf nodes remaining */ |
| 18 | + changed_t v; |
| 19 | + if (k == 2) { |
| 20 | + // changed_t v = fill_balanced_binary_tree(irem, root, lrem); |
| 21 | + v = grow_random_binary_tree(root, lrem); |
| 22 | + } else { |
16 | 23 | fprintf(stderr, "generic k-ary trees not supported yet (%d)\n", k);
|
17 |
| - throw 3; |
| 24 | + throw TREE_ERROR; |
18 | 25 | }
|
19 |
| - irem = n-1; |
20 |
| - lrem = n; |
21 |
| - changed_t v = fill_balanced_binary_tree(irem, root, lrem); |
22 |
| - // changed_t v = fill_binary_tree(irem, root, lrem); |
| 26 | + |
23 | 27 | if (v.inner != irem || v.leaf != lrem) {
|
24 | 28 | fprintf(stderr, "Didn't fill tree correctly: (irem=%ld lrem=%ld, n=%ld)\n",
|
25 | 29 | v.inner, v.leaf, n_);
|
26 |
| - throw 3; |
| 30 | + throw TREE_ERROR; |
27 | 31 | }
|
28 | 32 | }
|
29 | 33 |
|
30 |
| -FLOAT_T random_kary_tree::sum_tree() |
| 34 | +FLOAT_T random_reduction_tree::sum_tree() |
31 | 35 | {
|
32 | 36 | return 0.0/0.0;
|
33 | 37 | }
|
34 | 38 |
|
35 |
| -FLOAT_T random_kary_tree::multiply_tree() |
| 39 | +FLOAT_T random_reduction_tree::multiply_tree() |
36 | 40 | {
|
37 | 41 | return 0.0/0.0;
|
38 | 42 | }
|
39 | 43 |
|
40 |
| -changed_t random_kary_tree::fill_balanced_binary_tree( |
| 44 | +/* Make a balanced binary tree. Not random */ |
| 45 | +changed_t random_reduction_tree::fill_balanced_binary_tree( |
41 | 46 | long irem, tree<FLOAT_T>::iterator current, long lrem)
|
42 | 47 | {
|
43 | 48 | return (changed_t) {.inner = 0, .leaf = 0};
|
44 | 49 | }
|
45 | 50 |
|
46 |
| -/* Helper, recursive function for fill_random_kary_tree */ |
47 |
| -/* irem: The number of inner nodes remaining. |
| 51 | +/* Make a random binary tree. Algorithm R from The Art of Computer |
| 52 | + * Programming, Volume 4, pre-fascicle 4A: A Draft of Section 7.2.1.6: |
| 53 | + * Generating All Trees, Donald Knuth. |
| 54 | + * irem: The number of inner nodes remaining. |
48 | 55 | * t: Current node of the tree
|
49 | 56 | * lrem: Number of leaves remaining to add
|
50 | 57 | * A: Array of values to place in the tree. Removed from the right.
|
51 | 58 | * returns: The number of inner nodes and leaf nodes added in the subtree
|
52 | 59 | */
|
53 |
| -changed_t random_kary_tree::fill_binary_tree( |
54 |
| - long irem, tree<FLOAT_T>::iterator current, long lrem) |
| 60 | +changed_t random_reduction_tree::grow_random_binary_tree( |
| 61 | + tree<FLOAT_T>::iterator root, long lrem) |
55 | 62 | {
|
56 |
| - int dir = 0; |
57 |
| - changed_t rv {.inner = 0, .leaf = 0}; |
58 |
| - typename tree<FLOAT_T>::iterator l, r; |
59 |
| - /* To add another inner node we need at least 2 left in leaf budget */ |
60 |
| - if (irem > 0 && lrem >= 2) { |
61 |
| - dir = rand() % 2; |
62 |
| - } else { |
63 |
| - dir = 0; |
| 63 | + if ((2 * lrem + 1) >= RAND_MAX) { |
| 64 | + fprintf(stderr, "tree too big\n"); |
| 65 | + throw TREE_ERROR; |
64 | 66 | }
|
65 |
| - |
66 |
| - if (dir == 0) { /* I'm a leaf */ |
67 |
| - *current = A_[lrem - 1]; |
68 |
| - rv.leaf++; |
69 |
| - } else { /* I'm an inner node */ |
70 |
| - l = t.append_child(current, nan("")); |
71 |
| - r = t.append_child(current, nan("")); |
72 |
| - rv = fill_binary_tree(irem-1, l, lrem-1); // Save at least 1 leaf |
73 |
| - /* Subtract how much we filled on the left side */ |
74 |
| - rv = fill_binary_tree((n_-1)-rv.inner, r, n_-rv.leaf); |
| 67 | + /* Allocate an array */ |
| 68 | + long x, k, b, n, rem; |
| 69 | + long *L; |
| 70 | + L = (long *) malloc((2*lrem + 1)*sizeof(long)); |
| 71 | + /* Initialize (R1) */ |
| 72 | + n = 0; |
| 73 | + L[0] = 0; |
| 74 | + while (n < lrem) { /* Done? (R2) */ |
| 75 | + /* Advance i (R3) */ |
| 76 | + x = rand() % (4 * n + 1); |
| 77 | + n++; |
| 78 | + b = x % 2; |
| 79 | + k = x / 2; |
| 80 | + L[2*n - b] = 2*n; |
| 81 | + L[2*n - 1 + b] = L[k]; |
| 82 | + L[k] = 2*n - 1; |
| 83 | + } |
| 84 | + /* Debug */ |
| 85 | + printf("[%ld", L[0]); |
| 86 | + for (rem = 1; rem < 2 * lrem + 1; rem++) { |
| 87 | + printf(", %ld", L[rem]); |
75 | 88 | }
|
76 |
| - return rv; |
| 89 | + printf("]\n"); |
| 90 | + |
| 91 | + /* Now, to convert to C++ tree */ |
| 92 | + free(L); |
| 93 | + return (changed_t) {.inner = 0, .leaf = 0}; |
77 | 94 | }
|
78 | 95 |
|
79 | 96 | /* Explicit template instantiation. Here, we see two flavors, respectively:
|
80 | 97 | * classes and class member functions */
|
81 |
| -/* template class random_kary_tree<double>; */ |
82 |
| -/* template random_kary_tree<double>::random_kary_tree(int k, long n, double* A); */ |
| 98 | +/* template class random_reduction_tree<double>; */ |
| 99 | +/* template random_reduction_tree<double>::random_reduction_tree(int k, long n, double* A); */ |
83 | 100 |
|
0 commit comments