github.com/andybalholm/brotli@v1.0.6/cluster_command.go (about) 1 package brotli 2 3 /* Copyright 2013 Google Inc. All Rights Reserved. 4 5 Distributed under MIT license. 6 See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 7 */ 8 9 /* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if 10 it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */ 11 func compareAndPushToQueueCommand(out []histogramCommand, cluster_size []uint32, idx1 uint32, idx2 uint32, max_num_pairs uint, pairs []histogramPair, num_pairs *uint) { 12 var is_good_pair bool = false 13 var p histogramPair 14 p.idx2 = 0 15 p.idx1 = p.idx2 16 p.cost_combo = 0 17 p.cost_diff = p.cost_combo 18 if idx1 == idx2 { 19 return 20 } 21 22 if idx2 < idx1 { 23 var t uint32 = idx2 24 idx2 = idx1 25 idx1 = t 26 } 27 28 p.idx1 = idx1 29 p.idx2 = idx2 30 p.cost_diff = 0.5 * clusterCostDiff(uint(cluster_size[idx1]), uint(cluster_size[idx2])) 31 p.cost_diff -= out[idx1].bit_cost_ 32 p.cost_diff -= out[idx2].bit_cost_ 33 34 if out[idx1].total_count_ == 0 { 35 p.cost_combo = out[idx2].bit_cost_ 36 is_good_pair = true 37 } else if out[idx2].total_count_ == 0 { 38 p.cost_combo = out[idx1].bit_cost_ 39 is_good_pair = true 40 } else { 41 var threshold float64 42 if *num_pairs == 0 { 43 threshold = 1e99 44 } else { 45 threshold = brotli_max_double(0.0, pairs[0].cost_diff) 46 } 47 var combo histogramCommand = out[idx1] 48 var cost_combo float64 49 histogramAddHistogramCommand(&combo, &out[idx2]) 50 cost_combo = populationCostCommand(&combo) 51 if cost_combo < threshold-p.cost_diff { 52 p.cost_combo = cost_combo 53 is_good_pair = true 54 } 55 } 56 57 if is_good_pair { 58 p.cost_diff += p.cost_combo 59 if *num_pairs > 0 && histogramPairIsLess(&pairs[0], &p) { 60 /* Replace the top of the queue if needed. */ 61 if *num_pairs < max_num_pairs { 62 pairs[*num_pairs] = pairs[0] 63 (*num_pairs)++ 64 } 65 66 pairs[0] = p 67 } else if *num_pairs < max_num_pairs { 68 pairs[*num_pairs] = p 69 (*num_pairs)++ 70 } 71 } 72 } 73 74 func histogramCombineCommand(out []histogramCommand, cluster_size []uint32, symbols []uint32, clusters []uint32, pairs []histogramPair, num_clusters uint, symbols_size uint, max_clusters uint, max_num_pairs uint) uint { 75 var cost_diff_threshold float64 = 0.0 76 var min_cluster_size uint = 1 77 var num_pairs uint = 0 78 { 79 /* We maintain a vector of histogram pairs, with the property that the pair 80 with the maximum bit cost reduction is the first. */ 81 var idx1 uint 82 for idx1 = 0; idx1 < num_clusters; idx1++ { 83 var idx2 uint 84 for idx2 = idx1 + 1; idx2 < num_clusters; idx2++ { 85 compareAndPushToQueueCommand(out, cluster_size, clusters[idx1], clusters[idx2], max_num_pairs, pairs[0:], &num_pairs) 86 } 87 } 88 } 89 90 for num_clusters > min_cluster_size { 91 var best_idx1 uint32 92 var best_idx2 uint32 93 var i uint 94 if pairs[0].cost_diff >= cost_diff_threshold { 95 cost_diff_threshold = 1e99 96 min_cluster_size = max_clusters 97 continue 98 } 99 100 /* Take the best pair from the top of heap. */ 101 best_idx1 = pairs[0].idx1 102 103 best_idx2 = pairs[0].idx2 104 histogramAddHistogramCommand(&out[best_idx1], &out[best_idx2]) 105 out[best_idx1].bit_cost_ = pairs[0].cost_combo 106 cluster_size[best_idx1] += cluster_size[best_idx2] 107 for i = 0; i < symbols_size; i++ { 108 if symbols[i] == best_idx2 { 109 symbols[i] = best_idx1 110 } 111 } 112 113 for i = 0; i < num_clusters; i++ { 114 if clusters[i] == best_idx2 { 115 copy(clusters[i:], clusters[i+1:][:num_clusters-i-1]) 116 break 117 } 118 } 119 120 num_clusters-- 121 { 122 /* Remove pairs intersecting the just combined best pair. */ 123 var copy_to_idx uint = 0 124 for i = 0; i < num_pairs; i++ { 125 var p *histogramPair = &pairs[i] 126 if p.idx1 == best_idx1 || p.idx2 == best_idx1 || p.idx1 == best_idx2 || p.idx2 == best_idx2 { 127 /* Remove invalid pair from the queue. */ 128 continue 129 } 130 131 if histogramPairIsLess(&pairs[0], p) { 132 /* Replace the top of the queue if needed. */ 133 var front histogramPair = pairs[0] 134 pairs[0] = *p 135 pairs[copy_to_idx] = front 136 } else { 137 pairs[copy_to_idx] = *p 138 } 139 140 copy_to_idx++ 141 } 142 143 num_pairs = copy_to_idx 144 } 145 146 /* Push new pairs formed with the combined histogram to the heap. */ 147 for i = 0; i < num_clusters; i++ { 148 compareAndPushToQueueCommand(out, cluster_size, best_idx1, clusters[i], max_num_pairs, pairs[0:], &num_pairs) 149 } 150 } 151 152 return num_clusters 153 } 154 155 /* What is the bit cost of moving histogram from cur_symbol to candidate. */ 156 func histogramBitCostDistanceCommand(histogram *histogramCommand, candidate *histogramCommand) float64 { 157 if histogram.total_count_ == 0 { 158 return 0.0 159 } else { 160 var tmp histogramCommand = *histogram 161 histogramAddHistogramCommand(&tmp, candidate) 162 return populationCostCommand(&tmp) - candidate.bit_cost_ 163 } 164 }