cluster_inc.h 12 KB

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