Compute a permutation of eigenvalues to balance variance accross buckets of dimensions. Described in section 3.2.4 in http://research.microsoft.com/pubs/187499/cvpr13opq.pdf Note, the following slides indicate this function will break when fed eigenvalues < 1 without the scaling
(num_buckets, eigenvalues, shuffle=False)
| 99 | # |
| 100 | @_memory.cache |
| 101 | def eigenvalue_allocation(num_buckets, eigenvalues, shuffle=False): |
| 102 | """ |
| 103 | Compute a permutation of eigenvalues to balance variance accross buckets |
| 104 | of dimensions. |
| 105 | Described in section 3.2.4 in http://research.microsoft.com/pubs/187499/cvpr13opq.pdf |
| 106 | Note, the following slides indicate this function will break when fed eigenvalues < 1 |
| 107 | without the scaling trick implemented below: |
| 108 | https://www.robots.ox.ac.uk/~vgg/rg/slides/ge__cvpr2013__optimizedpq.pdf |
| 109 | :param int num_buckets: |
| 110 | the number of dimension buckets over which to allocate eigenvalues |
| 111 | :param ndarray eigenvalues: |
| 112 | a vector of eigenvalues |
| 113 | :param bool shuffle: |
| 114 | whether to randomly shuffle the order of resulting buckets |
| 115 | :returns ndarray: |
| 116 | a vector of indices by which to permute the eigenvectors |
| 117 | """ |
| 118 | D = len(eigenvalues) |
| 119 | dims_per_bucket = D / num_buckets |
| 120 | eigenvalue_product = np.zeros(num_buckets, dtype=float) |
| 121 | bucket_size = np.zeros(num_buckets, dtype=int) |
| 122 | permutation = np.zeros((num_buckets, dims_per_bucket), dtype=int) |
| 123 | |
| 124 | # We first must scale the eigenvalues by dividing by their |
| 125 | # smallets non-zero value to avoid problems with the algorithm |
| 126 | # when eigenvalues are less than 1. |
| 127 | min_non_zero_eigenvalue = np.min(np.abs(eigenvalues[np.nonzero(eigenvalues)])) |
| 128 | eigenvalues = eigenvalues / min_non_zero_eigenvalue |
| 129 | |
| 130 | # this is not actually a requirement, but I'm curious about whether this |
| 131 | # condition is ever violated |
| 132 | if not np.all(eigenvalues > 0): |
| 133 | print "WARNING: some eigenvalues were nonpositive" |
| 134 | |
| 135 | # Iterate eigenvalues in descending order |
| 136 | sorted_inds = np.argsort(eigenvalues)[::-1] |
| 137 | log_eigs = np.log2(abs(eigenvalues)) |
| 138 | for ind in sorted_inds: |
| 139 | |
| 140 | # Find eligible (not full) buckets |
| 141 | eligible = (bucket_size < dims_per_bucket).nonzero() |
| 142 | |
| 143 | # Find eligible bucket with least eigenvalue product |
| 144 | i = eigenvalue_product[eligible].argmin(0) |
| 145 | bucket = eligible[0][i] |
| 146 | |
| 147 | # Update eigenvalue product for this bucket |
| 148 | eigenvalue_product[bucket] = eigenvalue_product[bucket] + log_eigs[ind] |
| 149 | |
| 150 | # Store bucket assignment and update size |
| 151 | permutation[bucket, bucket_size[bucket]] = ind |
| 152 | bucket_size[bucket] += 1 |
| 153 | |
| 154 | if shuffle: |
| 155 | shuffle_idxs = np.arange(num_buckets, dtype=np.int) |
| 156 | np.random.shuffle(shuffle_idxs) |
| 157 | permutation = permutation[shuffle_idxs] |
| 158 |
no test coverage detected