brotli/enc/
cluster.rs

1#![allow(dead_code)]
2use super::bit_cost::BrotliPopulationCost;
3use super::histogram::{
4    CostAccessors, HistogramAddHistogram, HistogramClear, HistogramSelfAddHistogram,
5};
6use super::util::brotli_min_size_t;
7use super::util::FastLog2;
8use alloc;
9use alloc::{Allocator, SliceWrapper, SliceWrapperMut};
10use core;
11#[derive(Clone, Copy)]
12pub struct HistogramPair {
13    pub idx1: u32,
14    pub idx2: u32,
15    pub cost_combo: super::util::floatX,
16    pub cost_diff: super::util::floatX,
17}
18
19impl Default for HistogramPair {
20    #[inline(always)]
21    fn default() -> HistogramPair {
22        HistogramPair {
23            idx1: 0,
24            idx2: 0,
25            cost_combo: 0.0 as super::util::floatX,
26            cost_diff: 0.0 as super::util::floatX,
27        }
28    }
29}
30/* Returns entropy reduction of the context map when we combine two clusters. */
31#[inline(always)]
32fn ClusterCostDiff(size_a: usize, size_b: usize) -> super::util::floatX {
33    let size_c: usize = size_a.wrapping_add(size_b);
34    size_a as (super::util::floatX) * FastLog2(size_a as u64)
35        + size_b as (super::util::floatX) * FastLog2(size_b as u64)
36        - size_c as (super::util::floatX) * FastLog2(size_c as u64)
37}
38
39#[inline(always)]
40fn brotli_max_double(a: super::util::floatX, b: super::util::floatX) -> super::util::floatX {
41    if a > b {
42        a
43    } else {
44        b
45    }
46}
47
48#[inline(always)]
49fn HistogramPairIsLess(p1: &HistogramPair, p2: &HistogramPair) -> bool {
50    if p1.cost_diff != p2.cost_diff {
51        p1.cost_diff > p2.cost_diff
52    } else {
53        p1.idx2.wrapping_sub(p1.idx1) > p2.idx2.wrapping_sub(p2.idx1)
54    }
55}
56
57/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if
58it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */
59fn BrotliCompareAndPushToQueue<
60    HistogramType: SliceWrapperMut<u32> + SliceWrapper<u32> + CostAccessors + Clone,
61>(
62    out: &[HistogramType],
63    cluster_size: &[u32],
64    mut idx1: u32,
65    mut idx2: u32,
66    max_num_pairs: usize,
67    scratch_space: &mut HistogramType::i32vec,
68    pairs: &mut [HistogramPair],
69    num_pairs: &mut usize,
70) {
71    let mut is_good_pair: i32 = 0i32;
72    let mut p: HistogramPair = HistogramPair {
73        idx1: 0,
74        idx2: 0,
75        cost_combo: 0.0,
76        cost_diff: 0.0,
77    };
78    if idx1 == idx2 {
79    } else {
80        if idx2 < idx1 {
81            core::mem::swap(&mut idx2, &mut idx1);
82        }
83        p.idx1 = idx1;
84        p.idx2 = idx2;
85        p.cost_diff = 0.5 as super::util::floatX
86            * ClusterCostDiff(
87                cluster_size[idx1 as usize] as usize,
88                cluster_size[idx2 as usize] as usize,
89            );
90        p.cost_diff -= (out[idx1 as usize]).bit_cost();
91        p.cost_diff -= (out[idx2 as usize]).bit_cost();
92        if (out[idx1 as usize]).total_count() == 0usize {
93            p.cost_combo = (out[idx2 as usize]).bit_cost();
94            is_good_pair = 1i32;
95        } else if (out[idx2 as usize]).total_count() == 0usize {
96            p.cost_combo = (out[idx1 as usize]).bit_cost();
97            is_good_pair = 1i32;
98        } else {
99            let threshold: super::util::floatX = if *num_pairs == 0usize {
100                1e38 as super::util::floatX
101            } else {
102                brotli_max_double(0.0 as super::util::floatX, (pairs[0]).cost_diff)
103            };
104
105            let mut combo: HistogramType = out[idx1 as usize].clone();
106            HistogramAddHistogram(&mut combo, &out[idx2 as usize]);
107            let cost_combo: super::util::floatX = BrotliPopulationCost(&combo, scratch_space);
108            if cost_combo < threshold - p.cost_diff {
109                p.cost_combo = cost_combo;
110                is_good_pair = 1i32;
111            }
112        }
113        if is_good_pair != 0 {
114            p.cost_diff += p.cost_combo;
115            if *num_pairs > 0usize && HistogramPairIsLess(&pairs[0], &p) {
116                /* Replace the top of the queue if needed. */
117                if *num_pairs < max_num_pairs {
118                    pairs[*num_pairs] = pairs[0];
119                    *num_pairs = num_pairs.wrapping_add(1);
120                }
121                pairs[0] = p;
122            } else if *num_pairs < max_num_pairs {
123                pairs[*num_pairs] = p;
124                *num_pairs = num_pairs.wrapping_add(1);
125            }
126        }
127    }
128}
129
130pub fn BrotliHistogramCombine<
131    HistogramType: SliceWrapperMut<u32> + SliceWrapper<u32> + CostAccessors + Clone,
132>(
133    out: &mut [HistogramType],
134    cluster_size: &mut [u32],
135    symbols: &mut [u32],
136    clusters: &mut [u32],
137    pairs: &mut [HistogramPair],
138    mut num_clusters: usize,
139    symbols_size: usize,
140    max_clusters: usize,
141    max_num_pairs: usize,
142    scratch_space: &mut HistogramType::i32vec,
143) -> usize {
144    let mut cost_diff_threshold: super::util::floatX = 0.0 as super::util::floatX;
145    let mut min_cluster_size: usize = 1;
146    let mut num_pairs: usize = 0usize;
147    {
148        /* We maintain a vector of histogram pairs, with the property that the pair
149        with the maximum bit cost reduction is the first. */
150        let mut idx1: usize;
151        idx1 = 0usize;
152        while idx1 < num_clusters {
153            {
154                let mut idx2: usize;
155                idx2 = idx1.wrapping_add(1);
156                while idx2 < num_clusters {
157                    {
158                        BrotliCompareAndPushToQueue(
159                            out,
160                            cluster_size,
161                            clusters[idx1],
162                            clusters[idx2],
163                            max_num_pairs,
164                            scratch_space,
165                            pairs,
166                            &mut num_pairs,
167                        );
168                    }
169                    idx2 = idx2.wrapping_add(1);
170                }
171            }
172            idx1 = idx1.wrapping_add(1);
173        }
174    }
175    while num_clusters > min_cluster_size {
176        let mut i: usize;
177        if (pairs[0]).cost_diff >= cost_diff_threshold {
178            cost_diff_threshold = 1e38 as super::util::floatX;
179            min_cluster_size = max_clusters;
180            {
181                {
182                    continue;
183                }
184            }
185        }
186        /* Take the best pair from the top of heap. */
187        let best_idx1: u32 = (pairs[0]).idx1;
188        let best_idx2: u32 = (pairs[0]).idx2;
189        HistogramSelfAddHistogram(out, (best_idx1 as usize), (best_idx2 as usize));
190        (out[(best_idx1 as usize)]).set_bit_cost((pairs[0]).cost_combo);
191        {
192            let _rhs = cluster_size[(best_idx2 as usize)];
193            let _lhs = &mut cluster_size[(best_idx1 as usize)];
194            *_lhs = (*_lhs).wrapping_add(_rhs);
195        }
196        i = 0usize;
197        while i < symbols_size {
198            {
199                if symbols[i] == best_idx2 {
200                    symbols[i] = best_idx1;
201                }
202            }
203            i = i.wrapping_add(1);
204        }
205        i = 0usize;
206        'break9: while i < num_clusters {
207            {
208                if clusters[i] == best_idx2 {
209                    for offset in 0..(num_clusters - i - 1) {
210                        clusters[i + offset] = clusters[i + 1 + offset];
211                    }
212                    break 'break9;
213                }
214            }
215            i = i.wrapping_add(1);
216        }
217        num_clusters = num_clusters.wrapping_sub(1);
218        {
219            /* Remove pairs intersecting the just combined best pair. */
220            let mut copy_to_idx: usize = 0usize;
221            i = 0usize;
222            while i < num_pairs {
223                'continue12: loop {
224                    {
225                        let p: HistogramPair = pairs[i];
226                        if (p).idx1 == best_idx1
227                            || (p).idx2 == best_idx1
228                            || (p).idx1 == best_idx2
229                            || (p).idx2 == best_idx2
230                        {
231                            /* Remove invalid pair from the queue. */
232                            {
233                                break 'continue12;
234                            }
235                        }
236                        if HistogramPairIsLess(&pairs[0], &p) {
237                            /* Replace the top of the queue if needed. */
238                            let front: HistogramPair = pairs[0];
239                            pairs[0] = p;
240                            pairs[copy_to_idx] = front;
241                        } else {
242                            pairs[copy_to_idx] = p;
243                        }
244                        copy_to_idx = copy_to_idx.wrapping_add(1);
245                    }
246                    break;
247                }
248                i = i.wrapping_add(1);
249            }
250            num_pairs = copy_to_idx;
251        }
252        i = 0usize;
253        /* Push new pairs formed with the combined histogram to the heap. */
254        while i < num_clusters {
255            {
256                BrotliCompareAndPushToQueue(
257                    out,
258                    cluster_size,
259                    best_idx1,
260                    clusters[i],
261                    max_num_pairs,
262                    scratch_space,
263                    pairs,
264                    &mut num_pairs,
265                );
266            }
267            i = i.wrapping_add(1);
268        }
269    }
270    num_clusters
271}
272
273/* What is the bit cost of moving histogram from cur_symbol to candidate. */
274#[inline(always)]
275pub fn BrotliHistogramBitCostDistance<
276    HistogramType: SliceWrapperMut<u32> + SliceWrapper<u32> + CostAccessors + Clone,
277>(
278    histogram: &HistogramType,
279    candidate: &HistogramType,
280    scratch_space: &mut HistogramType::i32vec,
281) -> super::util::floatX {
282    if histogram.total_count() == 0usize {
283        0.0 as super::util::floatX
284    } else {
285        let mut tmp: HistogramType = histogram.clone();
286        HistogramAddHistogram(&mut tmp, candidate);
287        BrotliPopulationCost(&tmp, scratch_space) - candidate.bit_cost()
288    }
289}
290
291/* Find the best 'out' histogram for each of the 'in' histograms.
292When called, clusters[0..num_clusters) contains the unique values from
293symbols[0..in_size), but this property is not preserved in this function.
294Note: we assume that out[]->bit_cost_ is already up-to-date. */
295
296pub fn BrotliHistogramRemap<
297    HistogramType: SliceWrapperMut<u32> + SliceWrapper<u32> + CostAccessors + Clone,
298>(
299    inp: &[HistogramType],
300    in_size: usize,
301    clusters: &[u32],
302    num_clusters: usize,
303    scratch_space: &mut HistogramType::i32vec,
304    out: &mut [HistogramType],
305    symbols: &mut [u32],
306) {
307    let mut i: usize;
308    i = 0usize;
309    while i < in_size {
310        {
311            let mut best_out: u32 = if i == 0usize {
312                symbols[0]
313            } else {
314                symbols[i.wrapping_sub(1)]
315            };
316            let mut best_bits: super::util::floatX = BrotliHistogramBitCostDistance(
317                &inp[i],
318                &mut out[(best_out as usize)],
319                scratch_space,
320            );
321            let mut j: usize;
322            j = 0usize;
323            while j < num_clusters {
324                {
325                    let cur_bits: super::util::floatX = BrotliHistogramBitCostDistance(
326                        &inp[i],
327                        &mut out[(clusters[j] as usize)],
328                        scratch_space,
329                    );
330                    if cur_bits < best_bits {
331                        best_bits = cur_bits;
332                        best_out = clusters[j];
333                    }
334                }
335                j = j.wrapping_add(1);
336            }
337            symbols[i] = best_out;
338        }
339        i = i.wrapping_add(1);
340    }
341    i = 0usize;
342    /* Recompute each out based on raw and symbols. */
343    while i < num_clusters {
344        {
345            HistogramClear(&mut out[(clusters[i] as usize)]);
346        }
347        i = i.wrapping_add(1);
348    }
349    i = 0usize;
350    while i < in_size {
351        {
352            HistogramAddHistogram(&mut out[(symbols[i] as usize)], &inp[i]);
353        }
354        i = i.wrapping_add(1);
355    }
356}
357
358/* Reorders elements of the out[0..length) array and changes values in
359symbols[0..length) array in the following way:
360  * when called, symbols[] contains indexes into out[], and has N unique
361    values (possibly N < length)
362  * on return, symbols'[i] = f(symbols[i]) and
363               out'[symbols'[i]] = out[symbols[i]], for each 0 <= i < length,
364    where f is a bijection between the range of symbols[] and [0..N), and
365    the first occurrences of values in symbols'[i] come in consecutive
366    increasing order.
367Returns N, the number of unique values in symbols[]. */
368pub fn BrotliHistogramReindex<
369    HistogramType: SliceWrapperMut<u32> + SliceWrapper<u32> + CostAccessors + Clone,
370    Alloc: alloc::Allocator<u32> + alloc::Allocator<HistogramType>,
371>(
372    alloc: &mut Alloc,
373    out: &mut [HistogramType],
374    symbols: &mut [u32],
375    length: usize,
376) -> usize {
377    static kInvalidIndex: u32 = !(0u32);
378    let mut new_index = if length != 0 {
379        <Alloc as Allocator<u32>>::alloc_cell(alloc, length)
380    } else {
381        <Alloc as Allocator<u32>>::AllocatedMemory::default()
382    };
383    let mut next_index: u32;
384    let mut tmp: <Alloc as Allocator<HistogramType>>::AllocatedMemory;
385    let mut i: usize;
386    i = 0usize;
387    while i < length {
388        {
389            new_index.slice_mut()[i] = kInvalidIndex;
390        }
391        i = i.wrapping_add(1);
392    }
393    next_index = 0u32;
394    i = 0usize;
395    while i < length {
396        {
397            if new_index.slice()[(symbols[i] as usize)] == kInvalidIndex {
398                new_index.slice_mut()[(symbols[i] as usize)] = next_index;
399                next_index = next_index.wrapping_add(1);
400            }
401        }
402        i = i.wrapping_add(1);
403    }
404    /* TODO: by using idea of "cycle-sort" we can avoid allocation of
405    tmp and reduce the number of copying by the factor of 2. */
406    tmp = if next_index != 0 {
407        <Alloc as Allocator<HistogramType>>::alloc_cell(alloc, next_index as usize)
408    } else {
409        <Alloc as Allocator<HistogramType>>::AllocatedMemory::default()
410    };
411    next_index = 0u32;
412    i = 0usize;
413    while i < length {
414        {
415            if new_index.slice()[(symbols[i] as usize)] == next_index {
416                tmp.slice_mut()[(next_index as usize)] = out[(symbols[i] as usize)].clone();
417                next_index = next_index.wrapping_add(1);
418            }
419            symbols[i] = new_index.slice()[(symbols[i] as usize)];
420        }
421        i = i.wrapping_add(1);
422    }
423    {
424        <Alloc as Allocator<u32>>::free_cell(alloc, new_index);
425    }
426    i = 0usize;
427    while i < next_index as usize {
428        {
429            out[i] = tmp.slice()[i].clone();
430        }
431        i = i.wrapping_add(1);
432    }
433    {
434        <Alloc as Allocator<HistogramType>>::free_cell(alloc, tmp)
435    }
436    next_index as usize
437}
438
439pub fn BrotliClusterHistograms<
440    HistogramType: SliceWrapperMut<u32> + SliceWrapper<u32> + CostAccessors + Clone,
441    Alloc: alloc::Allocator<u32> + alloc::Allocator<HistogramPair> + alloc::Allocator<HistogramType>,
442>(
443    alloc: &mut Alloc,
444    inp: &[HistogramType],
445    in_size: usize,
446    max_histograms: usize,
447    scratch_space: &mut HistogramType::i32vec,
448    out: &mut [HistogramType],
449    out_size: &mut usize,
450    histogram_symbols: &mut [u32],
451) {
452    let mut cluster_size = if in_size != 0 {
453        <Alloc as Allocator<u32>>::alloc_cell(alloc, in_size)
454    } else {
455        <Alloc as Allocator<u32>>::AllocatedMemory::default()
456    };
457    let mut clusters = if in_size != 0 {
458        <Alloc as Allocator<u32>>::alloc_cell(alloc, in_size)
459    } else {
460        <Alloc as Allocator<u32>>::AllocatedMemory::default()
461    };
462    let mut num_clusters: usize = 0usize;
463    let max_input_histograms: usize = 64usize;
464    let pairs_capacity: usize = max_input_histograms
465        .wrapping_mul(max_input_histograms)
466        .wrapping_div(2);
467    let mut pairs =
468        <Alloc as Allocator<HistogramPair>>::alloc_cell(alloc, pairs_capacity.wrapping_add(1));
469    let mut i: usize;
470    i = 0usize;
471    while i < in_size {
472        {
473            cluster_size.slice_mut()[i] = 1u32;
474        }
475        i = i.wrapping_add(1);
476    }
477    i = 0usize;
478    while i < in_size {
479        {
480            out[i] = inp[i].clone();
481            (out[i]).set_bit_cost(BrotliPopulationCost(&inp[i], scratch_space));
482            histogram_symbols[i] = i as u32;
483        }
484        i = i.wrapping_add(1);
485    }
486    i = 0usize;
487    while i < in_size {
488        {
489            let num_to_combine: usize =
490                brotli_min_size_t(in_size.wrapping_sub(i), max_input_histograms);
491
492            let mut j: usize;
493            j = 0usize;
494            while j < num_to_combine {
495                {
496                    clusters.slice_mut()[num_clusters.wrapping_add(j)] = i.wrapping_add(j) as u32;
497                }
498                j = j.wrapping_add(1);
499            }
500            let num_new_clusters: usize = BrotliHistogramCombine(
501                out,
502                cluster_size.slice_mut(),
503                &mut histogram_symbols[i..],
504                &mut clusters.slice_mut()[num_clusters..],
505                pairs.slice_mut(),
506                num_to_combine,
507                num_to_combine,
508                max_histograms,
509                pairs_capacity,
510                scratch_space,
511            );
512            num_clusters = num_clusters.wrapping_add(num_new_clusters);
513        }
514        i = i.wrapping_add(max_input_histograms);
515    }
516    {
517        let max_num_pairs: usize = brotli_min_size_t(
518            (64usize).wrapping_mul(num_clusters),
519            num_clusters.wrapping_div(2).wrapping_mul(num_clusters),
520        );
521        {
522            if pairs_capacity < max_num_pairs.wrapping_add(1) {
523                let mut _new_size: usize = if pairs_capacity == 0usize {
524                    max_num_pairs.wrapping_add(1)
525                } else {
526                    pairs_capacity
527                };
528                let mut new_array: <Alloc as Allocator<HistogramPair>>::AllocatedMemory;
529                while _new_size < max_num_pairs.wrapping_add(1) {
530                    _new_size = _new_size.wrapping_mul(2);
531                }
532                new_array = if _new_size != 0 {
533                    <Alloc as Allocator<HistogramPair>>::alloc_cell(alloc, _new_size)
534                } else {
535                    <Alloc as Allocator<HistogramPair>>::AllocatedMemory::default()
536                };
537                new_array.slice_mut()[..pairs_capacity]
538                    .clone_from_slice(&pairs.slice()[..pairs_capacity]);
539                <Alloc as Allocator<HistogramPair>>::free_cell(
540                    alloc,
541                    core::mem::replace(&mut pairs, new_array),
542                );
543            }
544        }
545        num_clusters = BrotliHistogramCombine(
546            out,
547            cluster_size.slice_mut(),
548            histogram_symbols,
549            clusters.slice_mut(),
550            pairs.slice_mut(),
551            num_clusters,
552            in_size,
553            max_histograms,
554            max_num_pairs,
555            scratch_space,
556        );
557    }
558    <Alloc as Allocator<HistogramPair>>::free_cell(alloc, pairs);
559    <Alloc as Allocator<u32>>::free_cell(alloc, cluster_size);
560    BrotliHistogramRemap(
561        inp,
562        in_size,
563        clusters.slice(),
564        num_clusters,
565        scratch_space,
566        out,
567        histogram_symbols,
568    );
569    <Alloc as Allocator<u32>>::free_cell(alloc, clusters);
570    *out_size = BrotliHistogramReindex(alloc, out, histogram_symbols, in_size);
571}
572
573/////////// DONE //////////////////////////