cluster_inc.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /* NOLINT(build/header_guard) */
  2. /* Copyright 2013 Google Inc. All Rights Reserved.
  3. Distributed under MIT license.
  4. See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
  5. */
  6. /* template parameters: FN, CODE */
  7. #define HistogramType FN(Histogram)
  8. /* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if
  9. it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */
  10. BROTLI_INTERNAL void FN(BrotliCompareAndPushToQueue)(
  11. const HistogramType* out, const uint32_t* cluster_size, uint32_t idx1,
  12. uint32_t idx2, size_t max_num_pairs, HistogramPair* pairs,
  13. size_t* num_pairs) CODE({
  14. int is_good_pair = 0;
  15. HistogramPair p;
  16. if (idx1 == idx2) {
  17. return;
  18. }
  19. if (idx2 < idx1) {
  20. uint32_t t = idx2;
  21. idx2 = idx1;
  22. idx1 = t;
  23. }
  24. p.idx1 = idx1;
  25. p.idx2 = idx2;
  26. p.cost_diff = 0.5 * ClusterCostDiff(cluster_size[idx1], cluster_size[idx2]);
  27. p.cost_diff -= out[idx1].bit_cost_;
  28. p.cost_diff -= out[idx2].bit_cost_;
  29. if (out[idx1].total_count_ == 0) {
  30. p.cost_combo = out[idx2].bit_cost_;
  31. is_good_pair = 1;
  32. } else if (out[idx2].total_count_ == 0) {
  33. p.cost_combo = out[idx1].bit_cost_;
  34. is_good_pair = 1;
  35. } else {
  36. double threshold = *num_pairs == 0 ? 1e99 :
  37. BROTLI_MAX(double, 0.0, pairs[0].cost_diff);
  38. HistogramType combo = out[idx1];
  39. double cost_combo;
  40. FN(HistogramAddHistogram)(&combo, &out[idx2]);
  41. cost_combo = FN(BrotliPopulationCost)(&combo);
  42. if (cost_combo < threshold - p.cost_diff) {
  43. p.cost_combo = cost_combo;
  44. is_good_pair = 1;
  45. }
  46. }
  47. if (is_good_pair) {
  48. p.cost_diff += p.cost_combo;
  49. if (*num_pairs > 0 && HistogramPairIsLess(&pairs[0], &p)) {
  50. /* Replace the top of the queue if needed. */
  51. if (*num_pairs < max_num_pairs) {
  52. pairs[*num_pairs] = pairs[0];
  53. ++(*num_pairs);
  54. }
  55. pairs[0] = p;
  56. } else if (*num_pairs < max_num_pairs) {
  57. pairs[*num_pairs] = p;
  58. ++(*num_pairs);
  59. }
  60. }
  61. })
  62. BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
  63. uint32_t* cluster_size,
  64. uint32_t* symbols,
  65. uint32_t* clusters,
  66. HistogramPair* pairs,
  67. size_t num_clusters,
  68. size_t symbols_size,
  69. size_t max_clusters,
  70. size_t max_num_pairs) CODE({
  71. double cost_diff_threshold = 0.0;
  72. size_t min_cluster_size = 1;
  73. size_t num_pairs = 0;
  74. {
  75. /* We maintain a vector of histogram pairs, with the property that the pair
  76. with the maximum bit cost reduction is the first. */
  77. size_t idx1;
  78. for (idx1 = 0; idx1 < num_clusters; ++idx1) {
  79. size_t idx2;
  80. for (idx2 = idx1 + 1; idx2 < num_clusters; ++idx2) {
  81. FN(BrotliCompareAndPushToQueue)(out, cluster_size, clusters[idx1],
  82. clusters[idx2], max_num_pairs, &pairs[0], &num_pairs);
  83. }
  84. }
  85. }
  86. while (num_clusters > min_cluster_size) {
  87. uint32_t best_idx1;
  88. uint32_t best_idx2;
  89. size_t i;
  90. if (pairs[0].cost_diff >= cost_diff_threshold) {
  91. cost_diff_threshold = 1e99;
  92. min_cluster_size = max_clusters;
  93. continue;
  94. }
  95. /* Take the best pair from the top of heap. */
  96. best_idx1 = pairs[0].idx1;
  97. best_idx2 = pairs[0].idx2;
  98. FN(HistogramAddHistogram)(&out[best_idx1], &out[best_idx2]);
  99. out[best_idx1].bit_cost_ = pairs[0].cost_combo;
  100. cluster_size[best_idx1] += cluster_size[best_idx2];
  101. for (i = 0; i < symbols_size; ++i) {
  102. if (symbols[i] == best_idx2) {
  103. symbols[i] = best_idx1;
  104. }
  105. }
  106. for (i = 0; i < num_clusters; ++i) {
  107. if (clusters[i] == best_idx2) {
  108. memmove(&clusters[i], &clusters[i + 1],
  109. (num_clusters - i - 1) * sizeof(clusters[0]));
  110. break;
  111. }
  112. }
  113. --num_clusters;
  114. {
  115. /* Remove pairs intersecting the just combined best pair. */
  116. size_t copy_to_idx = 0;
  117. for (i = 0; i < num_pairs; ++i) {
  118. HistogramPair* p = &pairs[i];
  119. if (p->idx1 == best_idx1 || p->idx2 == best_idx1 ||
  120. p->idx1 == best_idx2 || p->idx2 == best_idx2) {
  121. /* Remove invalid pair from the queue. */
  122. continue;
  123. }
  124. if (HistogramPairIsLess(&pairs[0], p)) {
  125. /* Replace the top of the queue if needed. */
  126. HistogramPair front = pairs[0];
  127. pairs[0] = *p;
  128. pairs[copy_to_idx] = front;
  129. } else {
  130. pairs[copy_to_idx] = *p;
  131. }
  132. ++copy_to_idx;
  133. }
  134. num_pairs = copy_to_idx;
  135. }
  136. /* Push new pairs formed with the combined histogram to the heap. */
  137. for (i = 0; i < num_clusters; ++i) {
  138. FN(BrotliCompareAndPushToQueue)(out, cluster_size, best_idx1, clusters[i],
  139. max_num_pairs, &pairs[0], &num_pairs);
  140. }
  141. }
  142. return num_clusters;
  143. })
  144. /* What is the bit cost of moving histogram from cur_symbol to candidate. */
  145. BROTLI_INTERNAL double FN(BrotliHistogramBitCostDistance)(
  146. const HistogramType* histogram, const HistogramType* candidate) CODE({
  147. if (histogram->total_count_ == 0) {
  148. return 0.0;
  149. } else {
  150. HistogramType tmp = *histogram;
  151. FN(HistogramAddHistogram)(&tmp, candidate);
  152. return FN(BrotliPopulationCost)(&tmp) - candidate->bit_cost_;
  153. }
  154. })
  155. /* Find the best 'out' histogram for each of the 'in' histograms.
  156. When called, clusters[0..num_clusters) contains the unique values from
  157. symbols[0..in_size), but this property is not preserved in this function.
  158. Note: we assume that out[]->bit_cost_ is already up-to-date. */
  159. BROTLI_INTERNAL void FN(BrotliHistogramRemap)(const HistogramType* in,
  160. size_t in_size, const uint32_t* clusters, size_t num_clusters,
  161. HistogramType* out, uint32_t* symbols) CODE({
  162. size_t i;
  163. for (i = 0; i < in_size; ++i) {
  164. uint32_t best_out = i == 0 ? symbols[0] : symbols[i - 1];
  165. double best_bits =
  166. FN(BrotliHistogramBitCostDistance)(&in[i], &out[best_out]);
  167. size_t j;
  168. for (j = 0; j < num_clusters; ++j) {
  169. const double cur_bits =
  170. FN(BrotliHistogramBitCostDistance)(&in[i], &out[clusters[j]]);
  171. if (cur_bits < best_bits) {
  172. best_bits = cur_bits;
  173. best_out = clusters[j];
  174. }
  175. }
  176. symbols[i] = best_out;
  177. }
  178. /* Recompute each out based on raw and symbols. */
  179. for (i = 0; i < num_clusters; ++i) {
  180. FN(HistogramClear)(&out[clusters[i]]);
  181. }
  182. for (i = 0; i < in_size; ++i) {
  183. FN(HistogramAddHistogram)(&out[symbols[i]], &in[i]);
  184. }
  185. })
  186. /* Reorders elements of the out[0..length) array and changes values in
  187. symbols[0..length) array in the following way:
  188. * when called, symbols[] contains indexes into out[], and has N unique
  189. values (possibly N < length)
  190. * on return, symbols'[i] = f(symbols[i]) and
  191. out'[symbols'[i]] = out[symbols[i]], for each 0 <= i < length,
  192. where f is a bijection between the range of symbols[] and [0..N), and
  193. the first occurrences of values in symbols'[i] come in consecutive
  194. increasing order.
  195. Returns N, the number of unique values in symbols[]. */
  196. BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
  197. HistogramType* out, uint32_t* symbols, size_t length) CODE({
  198. static const uint32_t kInvalidIndex = BROTLI_UINT32_MAX;
  199. uint32_t* new_index = BROTLI_ALLOC(m, uint32_t, length);
  200. uint32_t next_index;
  201. HistogramType* tmp;
  202. size_t i;
  203. if (BROTLI_IS_OOM(m)) return 0;
  204. for (i = 0; i < length; ++i) {
  205. new_index[i] = kInvalidIndex;
  206. }
  207. next_index = 0;
  208. for (i = 0; i < length; ++i) {
  209. if (new_index[symbols[i]] == kInvalidIndex) {
  210. new_index[symbols[i]] = next_index;
  211. ++next_index;
  212. }
  213. }
  214. /* TODO: by using idea of "cycle-sort" we can avoid allocation of
  215. tmp and reduce the number of copying by the factor of 2. */
  216. tmp = BROTLI_ALLOC(m, HistogramType, next_index);
  217. if (BROTLI_IS_OOM(m)) return 0;
  218. next_index = 0;
  219. for (i = 0; i < length; ++i) {
  220. if (new_index[symbols[i]] == next_index) {
  221. tmp[next_index] = out[symbols[i]];
  222. ++next_index;
  223. }
  224. symbols[i] = new_index[symbols[i]];
  225. }
  226. BROTLI_FREE(m, new_index);
  227. for (i = 0; i < next_index; ++i) {
  228. out[i] = tmp[i];
  229. }
  230. BROTLI_FREE(m, tmp);
  231. return next_index;
  232. })
  233. BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
  234. MemoryManager* m, const HistogramType* in, const size_t in_size,
  235. size_t max_histograms, HistogramType* out, size_t* out_size,
  236. uint32_t* histogram_symbols) CODE({
  237. uint32_t* cluster_size = BROTLI_ALLOC(m, uint32_t, in_size);
  238. uint32_t* clusters = BROTLI_ALLOC(m, uint32_t, in_size);
  239. size_t num_clusters = 0;
  240. const size_t max_input_histograms = 64;
  241. size_t pairs_capacity = max_input_histograms * max_input_histograms / 2;
  242. /* For the first pass of clustering, we allow all pairs. */
  243. HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity + 1);
  244. size_t i;
  245. if (BROTLI_IS_OOM(m)) return;
  246. for (i = 0; i < in_size; ++i) {
  247. cluster_size[i] = 1;
  248. }
  249. for (i = 0; i < in_size; ++i) {
  250. out[i] = in[i];
  251. out[i].bit_cost_ = FN(BrotliPopulationCost)(&in[i]);
  252. histogram_symbols[i] = (uint32_t)i;
  253. }
  254. for (i = 0; i < in_size; i += max_input_histograms) {
  255. size_t num_to_combine =
  256. BROTLI_MIN(size_t, in_size - i, max_input_histograms);
  257. size_t num_new_clusters;
  258. size_t j;
  259. for (j = 0; j < num_to_combine; ++j) {
  260. clusters[num_clusters + j] = (uint32_t)(i + j);
  261. }
  262. num_new_clusters =
  263. FN(BrotliHistogramCombine)(out, cluster_size,
  264. &histogram_symbols[i],
  265. &clusters[num_clusters], pairs,
  266. num_to_combine, num_to_combine,
  267. max_histograms, pairs_capacity);
  268. num_clusters += num_new_clusters;
  269. }
  270. {
  271. /* For the second pass, we limit the total number of histogram pairs.
  272. After this limit is reached, we only keep searching for the best pair. */
  273. size_t max_num_pairs = BROTLI_MIN(size_t,
  274. 64 * num_clusters, (num_clusters / 2) * num_clusters);
  275. BROTLI_ENSURE_CAPACITY(
  276. m, HistogramPair, pairs, pairs_capacity, max_num_pairs + 1);
  277. if (BROTLI_IS_OOM(m)) return;
  278. /* Collapse similar histograms. */
  279. num_clusters = FN(BrotliHistogramCombine)(out, cluster_size,
  280. histogram_symbols, clusters,
  281. pairs, num_clusters, in_size,
  282. max_histograms, max_num_pairs);
  283. }
  284. BROTLI_FREE(m, pairs);
  285. BROTLI_FREE(m, cluster_size);
  286. /* Find the optimal map from original histograms to the final ones. */
  287. FN(BrotliHistogramRemap)(in, in_size, clusters, num_clusters,
  288. out, histogram_symbols);
  289. BROTLI_FREE(m, clusters);
  290. /* Convert the context map to a canonical form. */
  291. *out_size = FN(BrotliHistogramReindex)(m, out, histogram_symbols, in_size);
  292. if (BROTLI_IS_OOM(m)) return;
  293. })
  294. #undef HistogramType