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 | }
|
---|