/* What is the bit cost of moving histogram from cur_symbol to candidate. */ public static double BrotliHistogramBitCostDistance( HistogramLiteral *histogram, HistogramLiteral *candidate) { if (histogram->total_count_ == 0) { return(0.0); } else { HistogramLiteral tmp = *histogram; HistogramLiteral.HistogramAddHistogram(&tmp, candidate); return(BitCostLiteral.BrotliPopulationCost(&tmp) - candidate->bit_cost_); } }
public static void BrotliCompareAndPushToQueue( HistogramLiteral *out_, uint *cluster_size, uint idx1, uint idx2, size_t max_num_pairs, HistogramPair *pairs, size_t *num_pairs) { bool is_good_pair = false; HistogramPair p = new HistogramPair(); if (idx1 == idx2) { return; } if (idx2 < idx1) { uint t = idx2; idx2 = idx1; idx1 = t; } p.idx1 = idx1; p.idx2 = idx2; p.cost_diff = 0.5 * ClusterCostDiff(cluster_size[idx1], cluster_size[idx2]); p.cost_diff -= out_[idx1].bit_cost_; p.cost_diff -= out_[idx2].bit_cost_; if (out_[idx1].total_count_ == 0) { p.cost_combo = out_[idx2].bit_cost_; is_good_pair = true; } else if (out_[idx2].total_count_ == 0) { p.cost_combo = out_[idx1].bit_cost_; is_good_pair = true; } else { double threshold = *num_pairs == 0 ? 1e99 : Math.Max(0.0, pairs[0].cost_diff); HistogramLiteral combo = out_[idx1]; double cost_combo; HistogramLiteral.HistogramAddHistogram(&combo, &out_[idx2]); cost_combo = BitCostLiteral.BrotliPopulationCost(&combo); if (cost_combo < threshold - p.cost_diff) { p.cost_combo = cost_combo; is_good_pair = true; } } if (is_good_pair) { p.cost_diff += p.cost_combo; if (*num_pairs > 0 && HistogramPairIsLess(&pairs[0], &p)) { /* Replace the top of the queue if needed. */ if (*num_pairs < max_num_pairs) { pairs[*num_pairs] = pairs[0]; ++(*num_pairs); } pairs[0] = p; } else if (*num_pairs < max_num_pairs) { pairs[*num_pairs] = p; ++(*num_pairs); } } }
public static void BrotliClusterHistograms( ref MemoryManager m, HistogramLiteral *in_, size_t in_size, size_t max_histograms, HistogramLiteral *out_, size_t *out_size, uint *histogram_symbols) { uint * cluster_size = (uint *)BrotliAllocate(ref m, in_size * sizeof(uint)); uint * clusters = (uint *)BrotliAllocate(ref m, in_size * sizeof(uint)); size_t num_clusters = 0; size_t max_input_histograms = 64; size_t pairs_capacity = max_input_histograms * max_input_histograms / 2; /* For the first pass of clustering, we allow all pairs. */ HistogramPair *pairs = (HistogramPair *)BrotliAllocate(ref m, (pairs_capacity + 1) * sizeof(HistogramPair)); size_t i; for (i = 0; i < in_size; ++i) { cluster_size[i] = 1; } for (i = 0; i < in_size; ++i) { out_[i] = in_[i]; out_[i].bit_cost_ = BitCostLiteral.BrotliPopulationCost(&in_[i]); histogram_symbols[i] = (uint)i; } for (i = 0; i < in_size; i += max_input_histograms) { size_t num_to_combine = Math.Min(in_size - i, max_input_histograms); size_t num_new_clusters; size_t j; for (j = 0; j < num_to_combine; ++j) { clusters[num_clusters + j] = (uint)(i + j); } num_new_clusters = BrotliHistogramCombine(out_, cluster_size, &histogram_symbols[i], &clusters[num_clusters], pairs, num_to_combine, num_to_combine, max_histograms, pairs_capacity); num_clusters += num_new_clusters; } { /* For the second pass, we limit the total number of histogram pairs. * After this limit is reached, we only keep searching for the best pair. */ size_t max_num_pairs = Math.Min( 64 * num_clusters, (num_clusters / 2) * num_clusters); BrotliEnsureCapacity(ref m, sizeof(HistogramPair), (void **)&pairs, &pairs_capacity, max_num_pairs + 1); /* Collapse similar histograms. */ num_clusters = BrotliHistogramCombine(out_, cluster_size, histogram_symbols, clusters, pairs, num_clusters, in_size, max_histograms, max_num_pairs); } BrotliFree(ref m, pairs); BrotliFree(ref m, cluster_size); /* Find the optimal map from original histograms to the final ones. */ BrotliHistogramRemap(in_, in_size, clusters, num_clusters, out_, histogram_symbols); BrotliFree(ref m, clusters); /* Convert the context map to a canonical form. */ *out_size = BrotliHistogramReindex(ref m, out_, histogram_symbols, in_size); }