cluster_inc.h 11 KB

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