Coverage Report

Created: 2026-09-14 07:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libjxl/lib/jxl/enc_ans.cc
Line
Count
Source
1
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
2
//
3
// Use of this source code is governed by a BSD-style
4
// license that can be found in the LICENSE file.
5
6
#include "lib/jxl/enc_ans.h"
7
8
#include <jxl/memory_manager.h>
9
#include <jxl/types.h>
10
11
#include <algorithm>
12
#include <array>
13
#include <cmath>
14
#include <cstddef>
15
#include <cstdint>
16
#include <limits>
17
#include <utility>
18
#include <vector>
19
20
#include "lib/jxl/ans_common.h"
21
#include "lib/jxl/ans_params.h"
22
#include "lib/jxl/base/bits.h"
23
#include "lib/jxl/base/common.h"
24
#include "lib/jxl/base/compiler_specific.h"
25
#include "lib/jxl/base/status.h"
26
#include "lib/jxl/common.h"
27
#include "lib/jxl/dec_ans.h"
28
#include "lib/jxl/enc_ans_params.h"
29
#include "lib/jxl/enc_ans_simd.h"
30
#include "lib/jxl/enc_aux_out.h"
31
#include "lib/jxl/enc_cluster.h"
32
#include "lib/jxl/enc_context_map.h"
33
#include "lib/jxl/enc_fields.h"
34
#include "lib/jxl/enc_huffman.h"
35
#include "lib/jxl/enc_lz77.h"
36
#include "lib/jxl/enc_params.h"
37
#include "lib/jxl/fields.h"
38
#include "lib/jxl/memory_manager_internal.h"
39
#include "lib/jxl/modular/options.h"
40
#include "lib/jxl/simd_util.h"
41
42
namespace jxl {
43
44
namespace {
45
46
#if (!JXL_IS_DEBUG_BUILD)
47
constexpr
48
#endif
49
    bool ans_fuzzer_friendly_ = false;
50
51
const int kMaxNumSymbolsForSmallCode = 2;
52
53
template <typename Writer>
54
10.0M
void StoreVarLenUint8(size_t n, Writer* writer) {
55
10.0M
  JXL_DASSERT(n <= 255);
56
10.0M
  if (n == 0) {
57
975k
    writer->Write(1, 0);
58
9.12M
  } else {
59
9.12M
    writer->Write(1, 1);
60
9.12M
    size_t nbits = FloorLog2Nonzero(n);
61
9.12M
    writer->Write(3, nbits);
62
9.12M
    writer->Write(nbits, n - (1ULL << nbits));
63
9.12M
  }
64
10.0M
}
enc_ans.cc:void jxl::(anonymous namespace)::StoreVarLenUint8<jxl::SizeWriter>(unsigned long, jxl::SizeWriter*)
Line
Count
Source
54
9.79M
void StoreVarLenUint8(size_t n, Writer* writer) {
55
9.79M
  JXL_DASSERT(n <= 255);
56
9.79M
  if (n == 0) {
57
947k
    writer->Write(1, 0);
58
8.84M
  } else {
59
8.84M
    writer->Write(1, 1);
60
8.84M
    size_t nbits = FloorLog2Nonzero(n);
61
8.84M
    writer->Write(3, nbits);
62
8.84M
    writer->Write(nbits, n - (1ULL << nbits));
63
8.84M
  }
64
9.79M
}
enc_ans.cc:void jxl::(anonymous namespace)::StoreVarLenUint8<jxl::BitWriter>(unsigned long, jxl::BitWriter*)
Line
Count
Source
54
308k
void StoreVarLenUint8(size_t n, Writer* writer) {
55
308k
  JXL_DASSERT(n <= 255);
56
308k
  if (n == 0) {
57
27.9k
    writer->Write(1, 0);
58
281k
  } else {
59
281k
    writer->Write(1, 1);
60
281k
    size_t nbits = FloorLog2Nonzero(n);
61
281k
    writer->Write(3, nbits);
62
281k
    writer->Write(nbits, n - (1ULL << nbits));
63
281k
  }
64
308k
}
65
66
template <typename Writer>
67
52.8k
void StoreVarLenUint16(size_t n, Writer* writer) {
68
52.8k
  JXL_DASSERT(n <= 65535);
69
52.8k
  if (n == 0) {
70
635
    writer->Write(1, 0);
71
52.2k
  } else {
72
52.2k
    writer->Write(1, 1);
73
52.2k
    size_t nbits = FloorLog2Nonzero(n);
74
52.2k
    writer->Write(4, nbits);
75
52.2k
    writer->Write(nbits, n - (1ULL << nbits));
76
52.2k
  }
77
52.8k
}
enc_ans.cc:void jxl::(anonymous namespace)::StoreVarLenUint16<jxl::BitWriter>(unsigned long, jxl::BitWriter*)
Line
Count
Source
67
12.9k
void StoreVarLenUint16(size_t n, Writer* writer) {
68
12.9k
  JXL_DASSERT(n <= 65535);
69
12.9k
  if (n == 0) {
70
635
    writer->Write(1, 0);
71
12.2k
  } else {
72
12.2k
    writer->Write(1, 1);
73
12.2k
    size_t nbits = FloorLog2Nonzero(n);
74
12.2k
    writer->Write(4, nbits);
75
12.2k
    writer->Write(nbits, n - (1ULL << nbits));
76
12.2k
  }
77
12.9k
}
enc_ans.cc:void jxl::(anonymous namespace)::StoreVarLenUint16<jxl::SizeWriter>(unsigned long, jxl::SizeWriter*)
Line
Count
Source
67
39.9k
void StoreVarLenUint16(size_t n, Writer* writer) {
68
39.9k
  JXL_DASSERT(n <= 65535);
69
39.9k
  if (n == 0) {
70
0
    writer->Write(1, 0);
71
39.9k
  } else {
72
39.9k
    writer->Write(1, 1);
73
39.9k
    size_t nbits = FloorLog2Nonzero(n);
74
39.9k
    writer->Write(4, nbits);
75
39.9k
    writer->Write(nbits, n - (1ULL << nbits));
76
39.9k
  }
77
39.9k
}
78
79
class ANSEncodingHistogram {
80
 public:
81
232k
  const std::vector<ANSHistBin>& Counts() const { return counts_; }
82
1.29M
  float Cost() const { return cost_; }
83
  // The only way to construct valid histogram for ANS encoding
84
  static StatusOr<ANSEncodingHistogram> ComputeBest(
85
      const Histogram& histo,
86
1.29M
      HistogramParams::ANSHistogramStrategy ans_histogram_strategy) {
87
1.29M
    ANSEncodingHistogram result;
88
89
1.29M
    result.alphabet_size_ = histo.alphabet_size();
90
1.29M
    if (result.alphabet_size_ > ANS_MAX_ALPHABET_SIZE)
91
0
      return JXL_FAILURE("Too many entries in an ANS histogram");
92
93
1.29M
    if (result.alphabet_size_ > 0) {
94
      // Flat code
95
1.29M
      result.method_ = 0;
96
1.29M
      result.num_symbols_ = result.alphabet_size_;
97
1.29M
      result.counts_ = CreateFlatHistogram(result.alphabet_size_, ANS_TAB_SIZE);
98
      // in this case length can be non-suitable for SIMD - fix it
99
1.29M
      result.counts_.resize(histo.counts.size());
100
1.29M
      SizeWriter writer;
101
1.29M
      JXL_RETURN_IF_ERROR(result.Encode(&writer));
102
1.29M
      result.cost_ = writer.size + EstimateDataBitsFlat(histo);
103
1.29M
    } else {
104
      // Empty histogram
105
0
      result.method_ = 1;
106
0
      result.num_symbols_ = 0;
107
0
      result.cost_ = 3;
108
0
      return result;
109
0
    }
110
111
1.29M
    size_t symbol_count = 0;
112
48.7M
    for (size_t n = 0; n < result.alphabet_size_; ++n) {
113
47.4M
      if (histo.counts[n] > 0) {
114
20.2M
        if (symbol_count < kMaxNumSymbolsForSmallCode) {
115
2.44M
          result.symbols_[symbol_count] = n;
116
2.44M
        }
117
20.2M
        ++symbol_count;
118
20.2M
      }
119
47.4M
    }
120
1.29M
    result.num_symbols_ = symbol_count;
121
1.29M
    if (symbol_count == 1) {
122
      // Single-bin histogram
123
142k
      result.method_ = 1;
124
142k
      result.counts_ = histo.counts;
125
142k
      result.counts_[result.symbols_[0]] = ANS_TAB_SIZE;
126
142k
      SizeWriter writer;
127
142k
      JXL_RETURN_IF_ERROR(result.Encode(&writer));
128
142k
      result.cost_ = writer.size;
129
142k
      return result;
130
142k
    }
131
132
    // Here min 2 symbols
133
1.15M
    ANSEncodingHistogram normalized = result;
134
4.50M
    auto try_shift = [&](uint32_t shift) -> Status {
135
      // `shift = 12` and `shift = 11` are the same
136
4.50M
      normalized.method_ = std::min(shift, ANS_LOG_TAB_SIZE - 1) + 1;
137
138
4.50M
      if (!normalized.RebalanceHistogram(histo)) {
139
0
        return JXL_FAILURE("Logic error: couldn't rebalance a histogram");
140
0
      }
141
4.50M
      SizeWriter writer;
142
4.50M
      JXL_RETURN_IF_ERROR(normalized.Encode(&writer));
143
4.50M
      normalized.cost_ = writer.size + normalized.EstimateDataBits(histo);
144
4.50M
      if (normalized.cost_ < result.cost_) {
145
1.10M
        result = normalized;
146
1.10M
      }
147
4.50M
      return true;
148
4.50M
    };
149
150
1.15M
    switch (ans_histogram_strategy) {
151
31.3k
      case HistogramParams::ANSHistogramStrategy::kPrecise:
152
407k
        for (uint32_t shift = 0; shift < ANS_LOG_TAB_SIZE; shift++) {
153
376k
          JXL_RETURN_IF_ERROR(try_shift(shift));
154
376k
        }
155
31.3k
        break;
156
190k
      case HistogramParams::ANSHistogramStrategy::kApproximate:
157
1.52M
        for (uint32_t shift = 0; shift <= ANS_LOG_TAB_SIZE; shift += 2) {
158
1.33M
          JXL_RETURN_IF_ERROR(try_shift(shift));
159
1.33M
        }
160
190k
        break;
161
929k
      case HistogramParams::ANSHistogramStrategy::kFast:
162
929k
        JXL_RETURN_IF_ERROR(try_shift(0));
163
929k
        JXL_RETURN_IF_ERROR(try_shift(ANS_LOG_TAB_SIZE / 2));
164
929k
        JXL_RETURN_IF_ERROR(try_shift(ANS_LOG_TAB_SIZE));
165
929k
        break;
166
1.15M
    }
167
168
      // Sanity check
169
1.15M
#if JXL_IS_DEBUG_BUILD
170
1.15M
    JXL_ENSURE(histo.counts.size() == result.counts_.size());
171
1.15M
    ANSHistBin total = 0;  // Used only in assert.
172
48.1M
    for (size_t i = 0; i < result.alphabet_size_; ++i) {
173
46.9M
      JXL_ENSURE(result.counts_[i] >= 0);
174
      // For non-flat histogram values should be zero or non-zero simultaneously
175
      // for the same symbol in both initial and normalized histograms.
176
46.9M
      JXL_ENSURE(result.method_ == 0 ||
177
46.9M
                 (histo.counts[i] > 0) == (result.counts_[i] > 0));
178
      // Check accuracy of the histogram values
179
46.9M
      if (result.method_ > 0 && result.counts_[i] > 0 &&
180
14.5M
          i != result.omit_pos_) {
181
13.6M
        int logcounts = FloorLog2Nonzero<uint32_t>(result.counts_[i]);
182
13.6M
        int bitcount =
183
13.6M
            GetPopulationCountPrecision(logcounts, result.method_ - 1);
184
13.6M
        int drop_bits = logcounts - bitcount;
185
        // Check that the value is divisible by 2^drop_bits
186
13.6M
        JXL_ENSURE((result.counts_[i] & ((1 << drop_bits) - 1)) == 0);
187
13.6M
      }
188
46.9M
      total += result.counts_[i];
189
46.9M
    }
190
5.12M
    for (size_t i = result.alphabet_size_; i < result.counts_.size(); ++i) {
191
3.97M
      JXL_ENSURE(histo.counts[i] == 0);
192
3.97M
      JXL_ENSURE(result.counts_[i] == 0);
193
3.97M
    }
194
1.15M
    JXL_ENSURE((histo.total_count == 0) || (total == ANS_TAB_SIZE));
195
1.15M
#endif
196
1.15M
    return result;
197
1.15M
  }
198
199
  template <typename Writer>
200
6.15M
  Status Encode(Writer* writer) {
201
    // The check ensures also that all RLE sequences can be
202
    // encoded by `StoreVarLenUint8`
203
6.15M
    JXL_ENSURE(alphabet_size_ <= ANS_MAX_ALPHABET_SIZE);
204
205
    /// Flat histogram.
206
6.15M
    if (method_ == 0) {
207
      // Mark non-small tree.
208
1.30M
      writer->Write(1, 0);
209
      // Mark uniform histogram.
210
1.30M
      writer->Write(1, 1);
211
1.30M
      JXL_ENSURE(alphabet_size_ > 0);
212
      // Encode alphabet size.
213
1.30M
      StoreVarLenUint8(alphabet_size_ - 1, writer);
214
215
1.30M
      return true;
216
1.30M
    }
217
218
    /// Small tree.
219
4.85M
    if (num_symbols_ <= kMaxNumSymbolsForSmallCode) {
220
      // Small tree marker to encode 1-2 symbols.
221
198k
      writer->Write(1, 1);
222
198k
      if (num_symbols_ == 0) {
223
0
        writer->Write(1, 0);
224
0
        StoreVarLenUint8(0, writer);
225
198k
      } else {
226
198k
        writer->Write(1, num_symbols_ - 1);
227
444k
        for (size_t i = 0; i < num_symbols_; ++i) {
228
246k
          StoreVarLenUint8(symbols_[i], writer);
229
246k
        }
230
198k
      }
231
198k
      if (num_symbols_ == 2) {
232
48.1k
        writer->Write(ANS_LOG_TAB_SIZE, counts_[symbols_[0]]);
233
48.1k
      }
234
235
198k
      return true;
236
198k
    }
237
238
    /// General tree.
239
    // Mark non-small tree.
240
4.65M
    writer->Write(1, 0);
241
    // Mark non-flat histogram.
242
4.65M
    writer->Write(1, 0);
243
244
    // Elias gamma-like code for `shift = method - 1`. Only difference is that
245
    // if the number of bits to be encoded is equal to `upper_bound_log`,
246
    // we skip the terminating 0 in unary coding.
247
4.65M
    int upper_bound_log = FloorLog2Nonzero(ANS_LOG_TAB_SIZE + 1);
248
4.65M
    int log = FloorLog2Nonzero(method_);
249
4.65M
    writer->Write(log, (1 << log) - 1);
250
4.65M
    if (log != upper_bound_log) writer->Write(1, 0);
251
4.65M
    writer->Write(log, ((1 << log) - 1) & method_);
252
253
    // Since `num_symbols_ >= 3`, we know that `alphabet_size_ >= 3`, therefore
254
    // we encode `alphabet_size_ - 3`.
255
4.65M
    StoreVarLenUint8(alphabet_size_ - 3, writer);
256
257
    // Precompute sequences for RLE encoding. Contains the number of identical
258
    // values starting at a given index. Only contains that value at the first
259
    // element of the series.
260
4.65M
    uint8_t same[ANS_MAX_ALPHABET_SIZE] = {};
261
4.65M
    size_t last = 0;
262
196M
    for (size_t i = 1; i <= alphabet_size_; i++) {
263
      // Store the sequence length once different symbol reached, or we are
264
      // near the omit_pos_, or we're at the end. We don't support including the
265
      // omit_pos_ in an RLE sequence because this value may use a different
266
      // amount of log2 bits than standard, it is too complex to handle in the
267
      // decoder.
268
191M
      if (i == alphabet_size_ || i == omit_pos_ || i == omit_pos_ + 1 ||
269
180M
          counts_[i] != counts_[last]) {
270
88.6M
        same[last] = i - last;
271
88.6M
        last = i;
272
88.6M
      }
273
191M
    }
274
275
4.65M
    uint8_t bit_width[ANS_MAX_ALPHABET_SIZE] = {};
276
    // Use shortest possible Huffman code to encode `omit_pos` (see
277
    // `kBitWidthLengths`). `bit_width` value at `omit_pos` should be the
278
    // first of maximal values in the whole `bit_width` array, so it can be
279
    // increased without changing that property
280
4.65M
    int omit_width = 10;
281
196M
    for (size_t i = 0; i < alphabet_size_; ++i) {
282
191M
      if (i != omit_pos_ && counts_[i] > 0) {
283
74.7M
        bit_width[i] = FloorLog2Nonzero<uint32_t>(counts_[i]) + 1;
284
74.7M
        omit_width = std::max(omit_width, bit_width[i] + int{i < omit_pos_});
285
74.7M
      }
286
191M
    }
287
4.65M
    bit_width[omit_pos_] = static_cast<uint8_t>(omit_width);
288
289
    // The bit widths are encoded with a static Huffman code.
290
    // The last symbol is used as RLE sequence.
291
4.65M
    constexpr uint8_t kBitWidthLengths[ANS_LOG_TAB_SIZE + 2] = {
292
4.65M
        5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 6, 7, 7,
293
4.65M
    };
294
4.65M
    constexpr uint8_t kBitWidthSymbols[ANS_LOG_TAB_SIZE + 2] = {
295
4.65M
        17, 11, 15, 3, 9, 7, 4, 2, 5, 6, 0, 33, 1, 65,
296
4.65M
    };
297
4.65M
    constexpr uint8_t kMinReps = 5;
298
4.65M
    constexpr size_t rep = ANS_LOG_TAB_SIZE + 1;
299
    // Encode count bit widths
300
112M
    for (size_t i = 0; i < alphabet_size_; ++i) {
301
107M
      writer->Write(kBitWidthLengths[bit_width[i]],
302
107M
                    kBitWidthSymbols[bit_width[i]]);
303
107M
      if (same[i] >= kMinReps) {
304
        // Encode the RLE symbol and skip the repeated ones.
305
3.89M
        writer->Write(kBitWidthLengths[rep], kBitWidthSymbols[rep]);
306
3.89M
        StoreVarLenUint8(same[i] - kMinReps, writer);
307
3.89M
        i += same[i] - 1;
308
3.89M
      }
309
107M
    }
310
    // Encode additional bits of accuracy
311
4.65M
    uint32_t shift = method_ - 1;
312
4.65M
    if (shift != 0) {  // otherwise `bitcount = 0`
313
81.8M
      for (size_t i = 0; i < alphabet_size_; ++i) {
314
78.4M
        if (bit_width[i] > 1 && i != omit_pos_) {
315
53.2M
          int bitcount = GetPopulationCountPrecision(bit_width[i] - 1, shift);
316
53.2M
          int drop_bits = bit_width[i] - 1 - bitcount;
317
53.2M
          JXL_DASSERT((counts_[i] & ((1 << drop_bits) - 1)) == 0);
318
53.2M
          writer->Write(bitcount, (counts_[i] >> drop_bits) - (1 << bitcount));
319
53.2M
        }
320
78.4M
        if (same[i] >= kMinReps) {
321
          // Skip symbols encoded by RLE.
322
2.73M
          i += same[i] - 1;
323
2.73M
        }
324
78.4M
      }
325
3.40M
    }
326
4.65M
    return true;
327
4.65M
  }
enc_ans.cc:jxl::Status jxl::(anonymous namespace)::ANSEncodingHistogram::Encode<jxl::SizeWriter>(jxl::SizeWriter*)
Line
Count
Source
200
5.93M
  Status Encode(Writer* writer) {
201
    // The check ensures also that all RLE sequences can be
202
    // encoded by `StoreVarLenUint8`
203
5.93M
    JXL_ENSURE(alphabet_size_ <= ANS_MAX_ALPHABET_SIZE);
204
205
    /// Flat histogram.
206
5.93M
    if (method_ == 0) {
207
      // Mark non-small tree.
208
1.29M
      writer->Write(1, 0);
209
      // Mark uniform histogram.
210
1.29M
      writer->Write(1, 1);
211
1.29M
      JXL_ENSURE(alphabet_size_ > 0);
212
      // Encode alphabet size.
213
1.29M
      StoreVarLenUint8(alphabet_size_ - 1, writer);
214
215
1.29M
      return true;
216
1.29M
    }
217
218
    /// Small tree.
219
4.64M
    if (num_symbols_ <= kMaxNumSymbolsForSmallCode) {
220
      // Small tree marker to encode 1-2 symbols.
221
189k
      writer->Write(1, 1);
222
189k
      if (num_symbols_ == 0) {
223
0
        writer->Write(1, 0);
224
0
        StoreVarLenUint8(0, writer);
225
189k
      } else {
226
189k
        writer->Write(1, num_symbols_ - 1);
227
425k
        for (size_t i = 0; i < num_symbols_; ++i) {
228
236k
          StoreVarLenUint8(symbols_[i], writer);
229
236k
        }
230
189k
      }
231
189k
      if (num_symbols_ == 2) {
232
46.6k
        writer->Write(ANS_LOG_TAB_SIZE, counts_[symbols_[0]]);
233
46.6k
      }
234
235
189k
      return true;
236
189k
    }
237
238
    /// General tree.
239
    // Mark non-small tree.
240
4.45M
    writer->Write(1, 0);
241
    // Mark non-flat histogram.
242
4.45M
    writer->Write(1, 0);
243
244
    // Elias gamma-like code for `shift = method - 1`. Only difference is that
245
    // if the number of bits to be encoded is equal to `upper_bound_log`,
246
    // we skip the terminating 0 in unary coding.
247
4.45M
    int upper_bound_log = FloorLog2Nonzero(ANS_LOG_TAB_SIZE + 1);
248
4.45M
    int log = FloorLog2Nonzero(method_);
249
4.45M
    writer->Write(log, (1 << log) - 1);
250
4.45M
    if (log != upper_bound_log) writer->Write(1, 0);
251
4.45M
    writer->Write(log, ((1 << log) - 1) & method_);
252
253
    // Since `num_symbols_ >= 3`, we know that `alphabet_size_ >= 3`, therefore
254
    // we encode `alphabet_size_ - 3`.
255
4.45M
    StoreVarLenUint8(alphabet_size_ - 3, writer);
256
257
    // Precompute sequences for RLE encoding. Contains the number of identical
258
    // values starting at a given index. Only contains that value at the first
259
    // element of the series.
260
4.45M
    uint8_t same[ANS_MAX_ALPHABET_SIZE] = {};
261
4.45M
    size_t last = 0;
262
190M
    for (size_t i = 1; i <= alphabet_size_; i++) {
263
      // Store the sequence length once different symbol reached, or we are
264
      // near the omit_pos_, or we're at the end. We don't support including the
265
      // omit_pos_ in an RLE sequence because this value may use a different
266
      // amount of log2 bits than standard, it is too complex to handle in the
267
      // decoder.
268
186M
      if (i == alphabet_size_ || i == omit_pos_ || i == omit_pos_ + 1 ||
269
174M
          counts_[i] != counts_[last]) {
270
85.4M
        same[last] = i - last;
271
85.4M
        last = i;
272
85.4M
      }
273
186M
    }
274
275
4.45M
    uint8_t bit_width[ANS_MAX_ALPHABET_SIZE] = {};
276
    // Use shortest possible Huffman code to encode `omit_pos` (see
277
    // `kBitWidthLengths`). `bit_width` value at `omit_pos` should be the
278
    // first of maximal values in the whole `bit_width` array, so it can be
279
    // increased without changing that property
280
4.45M
    int omit_width = 10;
281
190M
    for (size_t i = 0; i < alphabet_size_; ++i) {
282
186M
      if (i != omit_pos_ && counts_[i] > 0) {
283
71.9M
        bit_width[i] = FloorLog2Nonzero<uint32_t>(counts_[i]) + 1;
284
71.9M
        omit_width = std::max(omit_width, bit_width[i] + int{i < omit_pos_});
285
71.9M
      }
286
186M
    }
287
4.45M
    bit_width[omit_pos_] = static_cast<uint8_t>(omit_width);
288
289
    // The bit widths are encoded with a static Huffman code.
290
    // The last symbol is used as RLE sequence.
291
4.45M
    constexpr uint8_t kBitWidthLengths[ANS_LOG_TAB_SIZE + 2] = {
292
4.45M
        5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 6, 7, 7,
293
4.45M
    };
294
4.45M
    constexpr uint8_t kBitWidthSymbols[ANS_LOG_TAB_SIZE + 2] = {
295
4.45M
        17, 11, 15, 3, 9, 7, 4, 2, 5, 6, 0, 33, 1, 65,
296
4.45M
    };
297
4.45M
    constexpr uint8_t kMinReps = 5;
298
4.45M
    constexpr size_t rep = ANS_LOG_TAB_SIZE + 1;
299
    // Encode count bit widths
300
108M
    for (size_t i = 0; i < alphabet_size_; ++i) {
301
104M
      writer->Write(kBitWidthLengths[bit_width[i]],
302
104M
                    kBitWidthSymbols[bit_width[i]]);
303
104M
      if (same[i] >= kMinReps) {
304
        // Encode the RLE symbol and skip the repeated ones.
305
3.80M
        writer->Write(kBitWidthLengths[rep], kBitWidthSymbols[rep]);
306
3.80M
        StoreVarLenUint8(same[i] - kMinReps, writer);
307
3.80M
        i += same[i] - 1;
308
3.80M
      }
309
104M
    }
310
    // Encode additional bits of accuracy
311
4.45M
    uint32_t shift = method_ - 1;
312
4.45M
    if (shift != 0) {  // otherwise `bitcount = 0`
313
80.1M
      for (size_t i = 0; i < alphabet_size_; ++i) {
314
76.7M
        if (bit_width[i] > 1 && i != omit_pos_) {
315
52.1M
          int bitcount = GetPopulationCountPrecision(bit_width[i] - 1, shift);
316
52.1M
          int drop_bits = bit_width[i] - 1 - bitcount;
317
52.1M
          JXL_DASSERT((counts_[i] & ((1 << drop_bits) - 1)) == 0);
318
52.1M
          writer->Write(bitcount, (counts_[i] >> drop_bits) - (1 << bitcount));
319
52.1M
        }
320
76.7M
        if (same[i] >= kMinReps) {
321
          // Skip symbols encoded by RLE.
322
2.71M
          i += same[i] - 1;
323
2.71M
        }
324
76.7M
      }
325
3.31M
    }
326
4.45M
    return true;
327
4.45M
  }
enc_ans.cc:jxl::Status jxl::(anonymous namespace)::ANSEncodingHistogram::Encode<jxl::BitWriter>(jxl::BitWriter*)
Line
Count
Source
200
221k
  Status Encode(Writer* writer) {
201
    // The check ensures also that all RLE sequences can be
202
    // encoded by `StoreVarLenUint8`
203
221k
    JXL_ENSURE(alphabet_size_ <= ANS_MAX_ALPHABET_SIZE);
204
205
    /// Flat histogram.
206
221k
    if (method_ == 0) {
207
      // Mark non-small tree.
208
9.39k
      writer->Write(1, 0);
209
      // Mark uniform histogram.
210
9.39k
      writer->Write(1, 1);
211
9.39k
      JXL_ENSURE(alphabet_size_ > 0);
212
      // Encode alphabet size.
213
9.39k
      StoreVarLenUint8(alphabet_size_ - 1, writer);
214
215
9.39k
      return true;
216
9.39k
    }
217
218
    /// Small tree.
219
211k
    if (num_symbols_ <= kMaxNumSymbolsForSmallCode) {
220
      // Small tree marker to encode 1-2 symbols.
221
8.93k
      writer->Write(1, 1);
222
8.93k
      if (num_symbols_ == 0) {
223
0
        writer->Write(1, 0);
224
0
        StoreVarLenUint8(0, writer);
225
8.93k
      } else {
226
8.93k
        writer->Write(1, num_symbols_ - 1);
227
19.3k
        for (size_t i = 0; i < num_symbols_; ++i) {
228
10.4k
          StoreVarLenUint8(symbols_[i], writer);
229
10.4k
        }
230
8.93k
      }
231
8.93k
      if (num_symbols_ == 2) {
232
1.52k
        writer->Write(ANS_LOG_TAB_SIZE, counts_[symbols_[0]]);
233
1.52k
      }
234
235
8.93k
      return true;
236
8.93k
    }
237
238
    /// General tree.
239
    // Mark non-small tree.
240
202k
    writer->Write(1, 0);
241
    // Mark non-flat histogram.
242
202k
    writer->Write(1, 0);
243
244
    // Elias gamma-like code for `shift = method - 1`. Only difference is that
245
    // if the number of bits to be encoded is equal to `upper_bound_log`,
246
    // we skip the terminating 0 in unary coding.
247
202k
    int upper_bound_log = FloorLog2Nonzero(ANS_LOG_TAB_SIZE + 1);
248
202k
    int log = FloorLog2Nonzero(method_);
249
202k
    writer->Write(log, (1 << log) - 1);
250
202k
    if (log != upper_bound_log) writer->Write(1, 0);
251
202k
    writer->Write(log, ((1 << log) - 1) & method_);
252
253
    // Since `num_symbols_ >= 3`, we know that `alphabet_size_ >= 3`, therefore
254
    // we encode `alphabet_size_ - 3`.
255
202k
    StoreVarLenUint8(alphabet_size_ - 3, writer);
256
257
    // Precompute sequences for RLE encoding. Contains the number of identical
258
    // values starting at a given index. Only contains that value at the first
259
    // element of the series.
260
202k
    uint8_t same[ANS_MAX_ALPHABET_SIZE] = {};
261
202k
    size_t last = 0;
262
6.06M
    for (size_t i = 1; i <= alphabet_size_; i++) {
263
      // Store the sequence length once different symbol reached, or we are
264
      // near the omit_pos_, or we're at the end. We don't support including the
265
      // omit_pos_ in an RLE sequence because this value may use a different
266
      // amount of log2 bits than standard, it is too complex to handle in the
267
      // decoder.
268
5.86M
      if (i == alphabet_size_ || i == omit_pos_ || i == omit_pos_ + 1 ||
269
5.36M
          counts_[i] != counts_[last]) {
270
3.20M
        same[last] = i - last;
271
3.20M
        last = i;
272
3.20M
      }
273
5.86M
    }
274
275
202k
    uint8_t bit_width[ANS_MAX_ALPHABET_SIZE] = {};
276
    // Use shortest possible Huffman code to encode `omit_pos` (see
277
    // `kBitWidthLengths`). `bit_width` value at `omit_pos` should be the
278
    // first of maximal values in the whole `bit_width` array, so it can be
279
    // increased without changing that property
280
202k
    int omit_width = 10;
281
6.06M
    for (size_t i = 0; i < alphabet_size_; ++i) {
282
5.86M
      if (i != omit_pos_ && counts_[i] > 0) {
283
2.79M
        bit_width[i] = FloorLog2Nonzero<uint32_t>(counts_[i]) + 1;
284
2.79M
        omit_width = std::max(omit_width, bit_width[i] + int{i < omit_pos_});
285
2.79M
      }
286
5.86M
    }
287
202k
    bit_width[omit_pos_] = static_cast<uint8_t>(omit_width);
288
289
    // The bit widths are encoded with a static Huffman code.
290
    // The last symbol is used as RLE sequence.
291
202k
    constexpr uint8_t kBitWidthLengths[ANS_LOG_TAB_SIZE + 2] = {
292
202k
        5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 6, 7, 7,
293
202k
    };
294
202k
    constexpr uint8_t kBitWidthSymbols[ANS_LOG_TAB_SIZE + 2] = {
295
202k
        17, 11, 15, 3, 9, 7, 4, 2, 5, 6, 0, 33, 1, 65,
296
202k
    };
297
202k
    constexpr uint8_t kMinReps = 5;
298
202k
    constexpr size_t rep = ANS_LOG_TAB_SIZE + 1;
299
    // Encode count bit widths
300
4.12M
    for (size_t i = 0; i < alphabet_size_; ++i) {
301
3.92M
      writer->Write(kBitWidthLengths[bit_width[i]],
302
3.92M
                    kBitWidthSymbols[bit_width[i]]);
303
3.92M
      if (same[i] >= kMinReps) {
304
        // Encode the RLE symbol and skip the repeated ones.
305
86.2k
        writer->Write(kBitWidthLengths[rep], kBitWidthSymbols[rep]);
306
86.2k
        StoreVarLenUint8(same[i] - kMinReps, writer);
307
86.2k
        i += same[i] - 1;
308
86.2k
      }
309
3.92M
    }
310
    // Encode additional bits of accuracy
311
202k
    uint32_t shift = method_ - 1;
312
202k
    if (shift != 0) {  // otherwise `bitcount = 0`
313
1.74M
      for (size_t i = 0; i < alphabet_size_; ++i) {
314
1.66M
        if (bit_width[i] > 1 && i != omit_pos_) {
315
1.14M
          int bitcount = GetPopulationCountPrecision(bit_width[i] - 1, shift);
316
1.14M
          int drop_bits = bit_width[i] - 1 - bitcount;
317
1.14M
          JXL_DASSERT((counts_[i] & ((1 << drop_bits) - 1)) == 0);
318
1.14M
          writer->Write(bitcount, (counts_[i] >> drop_bits) - (1 << bitcount));
319
1.14M
        }
320
1.66M
        if (same[i] >= kMinReps) {
321
          // Skip symbols encoded by RLE.
322
28.2k
          i += same[i] - 1;
323
28.2k
        }
324
1.66M
      }
325
87.7k
    }
326
202k
    return true;
327
202k
  }
328
329
  void ANSBuildInfoTable(const AliasTable::Entry* table, size_t log_alpha_size,
330
232k
                         ANSEncSymbolInfo* info) {
331
    // Create valid alias table for empty streams
332
7.56M
    for (size_t s = 0; s < std::max(size_t{1}, alphabet_size_); ++s) {
333
7.33M
      const ANSHistBin freq = s == alphabet_size_ ? ANS_TAB_SIZE : counts_[s];
334
7.33M
      info[s].freq_ = static_cast<uint16_t>(freq);
335
7.33M
#ifdef USE_MULT_BY_RECIPROCAL
336
7.33M
      if (freq != 0) {
337
3.64M
        info[s].ifreq_ = ((1ull << RECIPROCAL_PRECISION) + info[s].freq_ - 1) /
338
3.64M
                         info[s].freq_;
339
3.69M
      } else {
340
3.69M
        info[s].ifreq_ =
341
3.69M
            1;  // Shouldn't matter (symbol shouldn't occur), but...
342
3.69M
      }
343
7.33M
#endif
344
7.33M
      info[s].reverse_map_.resize(freq);
345
7.33M
    }
346
232k
    size_t log_entry_size = ANS_LOG_TAB_SIZE - log_alpha_size;
347
232k
    size_t entry_size_minus_1 = (1 << log_entry_size) - 1;
348
952M
    for (int i = 0; i < ANS_TAB_SIZE; i++) {
349
951M
      AliasTable::Symbol s =
350
951M
          AliasTable::Lookup(table, i, log_entry_size, entry_size_minus_1);
351
951M
      info[s.value].reverse_map_[s.offset] = i;
352
951M
    }
353
232k
  }
354
355
 private:
356
1.29M
  ANSEncodingHistogram() {}
357
358
  // Fixed-point log2 LUT for values of [0,4096]
359
  using Lg2LUT = std::array<uint32_t, ANS_TAB_SIZE + 1>;
360
  static const Lg2LUT lg2;
361
362
4.50M
  float EstimateDataBits(const Histogram& histo) {
363
4.50M
    int64_t sum = 0;
364
190M
    for (size_t i = 0; i < alphabet_size_; ++i) {
365
      // += histogram[i] * -log(counts[i]/total_counts)
366
186M
      sum += histo.counts[i] * int64_t{lg2[counts_[i]]};
367
186M
    }
368
4.50M
    return (histo.total_count - ldexpf(sum, -31)) * ANS_LOG_TAB_SIZE;
369
4.50M
  }
370
371
1.29M
  static float EstimateDataBitsFlat(const Histogram& histo) {
372
1.29M
    size_t len = histo.alphabet_size();
373
1.29M
    int64_t flat_bits = int64_t{lg2[len]} * ANS_LOG_TAB_SIZE;
374
1.29M
    return ldexpf(histo.total_count * flat_bits, -31);
375
1.29M
  }
376
377
  struct CountsEntropy {
378
    ANSHistBin count : 16;     // allowed value of counts in a histogram bin
379
    ANSHistBin step_log : 16;  // log2 of increase step size (can use 5 bits)
380
    int32_t delta_lg2;  // change of log between that value and the next allowed
381
  };
382
383
  // Array is sorted by decreasing allowed counts for each possible shift.
384
  // Exclusion of single-bin histograms before `RebalanceHistogram` allows
385
  // to put count upper limit of 4095, and shifts of 11 and 12 produce the
386
  // same table
387
  using CountsArray =
388
      std::array<std::array<CountsEntropy, ANS_TAB_SIZE>, ANS_LOG_TAB_SIZE>;
389
  using CountsIndex =
390
      std::array<std::array<uint16_t, ANS_TAB_SIZE>, ANS_LOG_TAB_SIZE>;
391
  struct AllowedCounts {
392
    CountsArray array;
393
    CountsIndex index;
394
  };
395
  static const AllowedCounts allowed_counts;
396
397
  // Returns the difference between largest count that can be represented and is
398
  // smaller than "count" and smallest representable count larger than "count".
399
198M
  static uint32_t SmallestIncrementLog(uint32_t count, uint32_t shift) {
400
198M
    if (count == 0) return 0;
401
88.8M
    uint32_t bits = FloorLog2Nonzero(count);
402
88.8M
    uint32_t drop_bits = bits - GetPopulationCountPrecision(bits, shift);
403
88.8M
    return drop_bits;
404
198M
  }
405
  // We are growing/reducing histogram step by step trying to maximize total
406
  // entropy i.e. sum of `freq[n] * log[counts[n]]` with a given sum of
407
  // `counts[n]` chosen from `allowed_counts[shift]`. This sum is balanced by
408
  // the `counts[omit_pos_]` in the highest bin of histogram. We start from
409
  // close to correct solution and each time a step with maximum entropy
410
  // increase per unit of bin change is chosen. This greedy scheme is not
411
  // guaranteed to achieve the global maximum, but cannot produce invalid
412
  // histogram. We use a fixed-point approximation for logarithms and all
413
  // arithmetic is integer besides initial approximation. Sum of `freq` and each
414
  // of `lg2[counts]` are supposed to be limited to `int32_t` range, so that the
415
  // sum of their products should not exceed `int64_t`.
416
4.50M
  bool RebalanceHistogram(const Histogram& histo) {
417
4.50M
    constexpr ANSHistBin table_size = ANS_TAB_SIZE;
418
4.50M
    uint32_t shift = method_ - 1;
419
420
4.50M
    struct EntropyDelta {
421
4.50M
      ANSHistBin freq;   // initial count
422
4.50M
      size_t count_ind;  // index of current bin value in `allowed_counts`
423
4.50M
      size_t bin_ind;    // index of current bin in `counts`
424
4.50M
    };
425
    // Penalties corresponding to different step sizes - entropy decrease in
426
    // balancing bin, step of size (1 << ANS_LOG_TAB_SIZE - 1) is not possible
427
4.50M
    std::array<int64_t, ANS_LOG_TAB_SIZE - 1> balance_inc = {};
428
4.50M
    std::array<int64_t, ANS_LOG_TAB_SIZE - 1> balance_dec = {};
429
4.50M
    const auto& ac = allowed_counts.array[shift];
430
4.50M
    const auto& ai = allowed_counts.index[shift];
431
    // TODO(ivan) separate cases of shift >= 11 - all steps are 1 there, and
432
    // possibly 10 - all relevant steps are 2.
433
    // Total entropy change by a step: increase/decrease in current bin
434
    // together with corresponding decrease/increase in the balancing bin.
435
    // Inc steps increase current bin, dec steps decrease
436
1.30G
    const auto delta_entropy_inc = [&](const EntropyDelta& a) {
437
1.30G
      return a.freq * int64_t{ac[a.count_ind].delta_lg2} -
438
1.30G
             balance_inc[ac[a.count_ind].step_log];
439
1.30G
    };
440
206M
    const auto delta_entropy_dec = [&](const EntropyDelta& a) {
441
206M
      return a.freq * int64_t{ac[a.count_ind + 1].delta_lg2} -
442
206M
             balance_dec[ac[a.count_ind + 1].step_log];
443
206M
    };
444
    // Compare steps by entropy increase per unit of histogram bin change.
445
    // Truncation is OK here, accuracy is anyway better than float
446
637M
    const auto IncLess = [&](const EntropyDelta& a, const EntropyDelta& b) {
447
637M
      return delta_entropy_inc(a) >> ac[a.count_ind].step_log <
448
637M
             delta_entropy_inc(b) >> ac[b.count_ind].step_log;
449
637M
    };
450
100M
    const auto DecLess = [&](const EntropyDelta& a, const EntropyDelta& b) {
451
100M
      return delta_entropy_dec(a) >> ac[a.count_ind + 1].step_log <
452
100M
             delta_entropy_dec(b) >> ac[b.count_ind + 1].step_log;
453
100M
    };
454
    // Vector of adjustable bins from `allowed_counts`
455
4.50M
    std::vector<EntropyDelta> bins;
456
4.50M
    bins.reserve(256);
457
458
4.50M
    double norm = double{table_size} / histo.total_count;
459
460
4.50M
    size_t remainder_pos = 0;  // highest balancing bin in the histogram
461
4.50M
    int64_t max_freq = 0;
462
4.50M
    ANSHistBin rest = table_size;  // reserve of histogram counts to distribute
463
190M
    for (size_t n = 0; n < alphabet_size_; ++n) {
464
186M
      ANSHistBin freq = histo.counts[n];
465
186M
      if (freq > max_freq) {
466
9.30M
        remainder_pos = n;
467
9.30M
        max_freq = freq;
468
9.30M
      }
469
470
186M
      double target = freq * norm;  // rounding
471
      // Keep zeros and clamp nonzero freq counts to [1, table_size)
472
186M
      ANSHistBin count = std::max<ANSHistBin>(round(target), freq > 0);
473
186M
      count = std::min<ANSHistBin>(count, table_size - 1);
474
186M
      uint32_t step_log = SmallestIncrementLog(count, shift);
475
186M
      ANSHistBin inc = 1 << step_log;
476
186M
      count &= ~(inc - 1);
477
478
186M
      counts_[n] = count;
479
186M
      rest -= count;
480
186M
      if (target > 1.0) {
481
75.9M
        bins.push_back({freq, ai[count], n});
482
75.9M
      }
483
186M
    }
484
485
    // Delete the highest balancing bin from adjustable by `allowed_counts`
486
4.50M
    bins.erase(std::find_if(
487
4.50M
        bins.begin(), bins.end(),
488
21.7M
        [&](const EntropyDelta& a) { return a.bin_ind == remainder_pos; }));
489
    // From now on `rest` is the height of balancing bin,
490
    // here it can be negative, but will be tracted into positive domain later
491
4.50M
    rest += counts_[remainder_pos];
492
493
4.50M
    if (!bins.empty()) {
494
4.49M
      const uint32_t max_log = ac[1].step_log;
495
27.6M
      while (true) {
496
        // Update balancing bin penalties setting guards and tractors
497
242M
        for (uint32_t log = 0; log <= max_log; ++log) {
498
215M
          ANSHistBin delta = 1 << log;
499
215M
          if (rest >= table_size) {
500
            // Tract large `rest` into allowed domain:
501
0
            balance_inc[log] = 0;  // permit all inc steps
502
0
            balance_dec[log] = 0;  // forbid all dec steps
503
215M
          } else if (rest > 1) {
504
            // `rest` is OK, put guards against non-possible steps
505
215M
            balance_inc[log] =
506
215M
                rest > delta  // possible step
507
215M
                    ? max_freq * int64_t{lg2[rest] - lg2[rest - delta]}
508
215M
                    : std::numeric_limits<int64_t>::max();  // forbidden
509
215M
            balance_dec[log] =
510
215M
                rest + delta < table_size  // possible step
511
215M
                    ? max_freq * int64_t{lg2[rest + delta] - lg2[rest]}
512
215M
                    : 0;  // forbidden
513
215M
          } else {
514
            // Tract negative or zero `rest` into positive:
515
            // forbid all inc steps
516
437
            balance_inc[log] = std::numeric_limits<int64_t>::max();
517
            // permit all dec steps
518
437
            balance_dec[log] = std::numeric_limits<int64_t>::max();
519
437
          }
520
215M
        }
521
        // Try to increase entropy
522
27.6M
        auto best_bin_inc = std::max_element(bins.begin(), bins.end(), IncLess);
523
27.6M
        if (delta_entropy_inc(*best_bin_inc) > 0) {
524
          // Grow the bin with the best histogram entropy increase
525
21.8M
          rest -= 1 << ac[best_bin_inc->count_ind--].step_log;
526
21.8M
        } else {
527
          // This still implies that entropy is strictly increasing each step
528
          // (or `rest` is tracted into positive domain), so we cannot loop
529
          // infinitely
530
5.80M
          auto best_bin_dec =
531
5.80M
              std::min_element(bins.begin(), bins.end(), DecLess);
532
          // Break if no reverse steps can grow entropy (or valid)
533
5.80M
          if (delta_entropy_dec(*best_bin_dec) >= 0) break;
534
          // Decrease the bin with the best histogram entropy increase
535
1.30M
          rest += 1 << ac[++best_bin_dec->count_ind].step_log;
536
1.30M
        }
537
27.6M
      }
538
      // Set counts besides the balancing bin
539
71.4M
      for (auto& a : bins) counts_[a.bin_ind] = ac[a.count_ind].count;
540
541
      // The scheme works fine if we have room to grow `bit_width` of balancing
542
      // bin, otherwise we need to put balancing bin to the first bin of 12 bit
543
      // width. In this case both that bin and balancing one should be close to
544
      // 2048 in targets, so exchange of them will not produce much worse
545
      // histogram
546
38.5M
      for (size_t n = 0; n < remainder_pos; ++n) {
547
34.0M
        if (counts_[n] >= 2048) {
548
12.4k
          counts_[remainder_pos] = counts_[n];
549
12.4k
          remainder_pos = n;
550
12.4k
          break;
551
12.4k
        }
552
34.0M
      }
553
4.49M
    }
554
    // Set balancing bin
555
4.50M
    counts_[remainder_pos] = rest;
556
4.50M
    omit_pos_ = remainder_pos;
557
558
4.50M
    return counts_[remainder_pos] > 0;
559
4.50M
  }
560
561
  float cost_ = 0;
562
  uint32_t method_ = 0;
563
  size_t omit_pos_ = 0;
564
  size_t alphabet_size_ = 0;
565
  size_t num_symbols_ = 0;
566
  size_t symbols_[kMaxNumSymbolsForSmallCode] = {};
567
  std::vector<ANSHistBin> counts_{};
568
};
569
570
using AEH = ANSEncodingHistogram;
571
572
252
const AEH::Lg2LUT AEH::lg2 = [] {
573
252
  Lg2LUT lg2;
574
252
  lg2[0] = 0;  // for entropy calculations it is OK
575
1.03M
  for (size_t i = 1; i < lg2.size(); ++i) {
576
1.03M
    lg2[i] = round(ldexp(log2(i) / ANS_LOG_TAB_SIZE, 31));
577
1.03M
  }
578
252
  return lg2;
579
252
}();
580
581
252
const AEH::AllowedCounts AEH::allowed_counts = [] {
582
252
  AllowedCounts result;
583
584
3.27k
  for (uint32_t shift = 0; shift < result.array.size(); ++shift) {
585
3.02k
    auto& ac = result.array[shift];
586
3.02k
    auto& ai = result.index[shift];
587
3.02k
    ANSHistBin last = ~0;
588
3.02k
    size_t slot = 0;
589
    // TODO(eustas): are those "default" values relevant?
590
3.02k
    ac[0].delta_lg2 = 0;
591
3.02k
    ac[0].step_log = 0;
592
12.3M
    for (int32_t i = ac.size() - 1; i >= 0; --i) {
593
12.3M
      int32_t curr = i & ~((1 << SmallestIncrementLog(i, shift)) - 1);
594
12.3M
      if (curr == last) continue;
595
2.41M
      last = curr;
596
2.41M
      ac[slot].count = curr;
597
2.41M
      ai[curr] = slot;
598
2.41M
      if (curr == 0) {
599
        // Guards against non-possible steps:
600
        // at max value [0] - 0 (by init), at min value - max
601
3.02k
        ac[slot].delta_lg2 = std::numeric_limits<int32_t>::max();
602
3.02k
        ac[slot].step_log = 0;
603
2.41M
      } else if (slot > 0) {
604
2.40M
        ANSHistBin prev = ac[slot - 1].count;
605
2.40M
        ac[slot].delta_lg2 = round(ldexp(
606
2.40M
            log2(static_cast<double>(prev) / curr) / ANS_LOG_TAB_SIZE, 31));
607
2.40M
        ac[slot].step_log = FloorLog2Nonzero<uint32_t>(prev - curr);
608
2.40M
        prev = curr;
609
2.40M
      }
610
2.41M
      slot++;
611
2.41M
    }
612
3.02k
  }
613
614
252
  return result;
615
252
}();
616
617
}  // namespace
618
619
1.06M
StatusOr<float> Histogram::ANSPopulationCost() const {
620
1.06M
  if (counts.size() > ANS_MAX_ALPHABET_SIZE) {
621
0
    return std::numeric_limits<float>::max();
622
0
  }
623
1.06M
  JXL_ASSIGN_OR_RETURN(
624
1.06M
      ANSEncodingHistogram normalized,
625
1.06M
      ANSEncodingHistogram::ComputeBest(
626
1.06M
          *this, HistogramParams::ANSHistogramStrategy::kFast));
627
1.06M
  return normalized.Cost();
628
1.06M
}
629
630
// Returns an estimate or exact cost of encoding this histogram and the
631
// corresponding data.
632
StatusOr<size_t> EntropyEncodingData::BuildAndStoreANSEncodingData(
633
    JxlMemoryManager* memory_manager,
634
    HistogramParams::ANSHistogramStrategy ans_histogram_strategy,
635
285k
    const Histogram& histogram, BitWriter* writer) {
636
285k
  ANSEncSymbolInfo* info = encoding_info.back().data();
637
285k
  size_t size = histogram.alphabet_size();
638
285k
  if (use_prefix_code) {
639
52.7k
    size_t cost = 0;
640
52.7k
    if (size <= 1) return 0;
641
52.1k
    std::vector<uint32_t> histo(size);
642
410k
    for (size_t i = 0; i < size; i++) {
643
358k
      JXL_ENSURE(histogram.counts[i] >= 0);
644
358k
      histo[i] = histogram.counts[i];
645
358k
    }
646
52.1k
    std::vector<uint8_t> depths(size);
647
52.1k
    std::vector<uint16_t> bits(size);
648
52.1k
    if (writer == nullptr) {
649
39.9k
      BitWriter tmp_writer{memory_manager};
650
39.9k
      JXL_RETURN_IF_ERROR(tmp_writer.WithMaxBits(
651
39.9k
          8 * size + 8,  // safe upper bound
652
39.9k
          LayerType::Header, /*aux_out=*/nullptr, [&] {
653
39.9k
            return BuildAndStoreHuffmanTree(histo.data(), size, depths.data(),
654
39.9k
                                            bits.data(), &tmp_writer);
655
39.9k
          }));
656
39.9k
      cost = tmp_writer.BitsWritten();
657
39.9k
    } else {
658
12.2k
      size_t start = writer->BitsWritten();
659
12.2k
      JXL_RETURN_IF_ERROR(BuildAndStoreHuffmanTree(
660
12.2k
          histo.data(), size, depths.data(), bits.data(), writer));
661
12.2k
      cost = writer->BitsWritten() - start;
662
12.2k
    }
663
410k
    for (size_t i = 0; i < size; i++) {
664
358k
      info[i].bits = depths[i] == 0 ? 0 : bits[i];
665
358k
      info[i].depth = depths[i];
666
358k
    }
667
    // Estimate data cost.
668
410k
    for (size_t i = 0; i < size; i++) {
669
358k
      cost += histo[i] * info[i].depth;
670
358k
    }
671
52.1k
    return cost;
672
52.1k
  }
673
464k
  JXL_ASSIGN_OR_RETURN(
674
464k
      ANSEncodingHistogram normalized,
675
464k
      ANSEncodingHistogram::ComputeBest(histogram, ans_histogram_strategy));
676
677
  // TODO(eustas): fix: 2KiB on stack
678
464k
  AliasTable::Entry a[ANS_MAX_ALPHABET_SIZE];
679
680
464k
  JXL_RETURN_IF_ERROR(
681
464k
      InitAliasTable(normalized.Counts(), ANS_LOG_TAB_SIZE, log_alpha_size, a));
682
232k
  normalized.ANSBuildInfoTable(a, log_alpha_size, info);
683
232k
  if (writer != nullptr) {
684
    // size_t start = writer->BitsWritten();
685
221k
    JXL_RETURN_IF_ERROR(normalized.Encode(writer));
686
    // return writer->BitsWritten() - start;
687
221k
  }
688
232k
  return static_cast<size_t>(ceilf(normalized.Cost()));
689
232k
}
690
691
namespace {
692
693
Histogram HistogramFromSymbolInfo(
694
73
    const std::vector<ANSEncSymbolInfo>& encoding_info, bool use_prefix_code) {
695
73
  Histogram histo;
696
73
  histo.counts.resize(DivCeil(encoding_info.size(), Histogram::kRounding) *
697
73
                      Histogram::kRounding);
698
73
  histo.total_count = 0;
699
18.7k
  for (size_t i = 0; i < encoding_info.size(); ++i) {
700
18.6k
    const ANSEncSymbolInfo& info = encoding_info[i];
701
18.6k
    int count = use_prefix_code
702
18.6k
                    ? (info.depth ? (1u << (PREFIX_MAX_BITS - info.depth)) : 0)
703
18.6k
                    : info.freq_;
704
18.6k
    histo.counts[i] = count;
705
18.6k
    histo.total_count += count;
706
18.6k
  }
707
73
  return histo;
708
73
}
709
710
}  // namespace
711
712
Status EntropyEncodingData::ChooseUintConfigs(
713
    JxlMemoryManager* memory_manager, const HistogramParams& params,
714
    const std::vector<std::vector<Token>>& tokens,
715
87.0k
    std::vector<Histogram>& clustered_histograms) {
716
  // Set sane default `log_alpha_size`.
717
87.0k
  if (use_prefix_code) {
718
52.6k
    log_alpha_size = PREFIX_MAX_BITS;
719
52.6k
  } else if (params.streaming_mode) {
720
    // TODO(szabadka) Figure out if we can use lower values here.
721
210
    log_alpha_size = 8;
722
34.2k
  } else if (lz77.enabled) {
723
7.68k
    log_alpha_size = 8;
724
26.5k
  } else {
725
26.5k
    log_alpha_size = 7;
726
26.5k
  }
727
728
87.0k
  if (ans_fuzzer_friendly_) {
729
0
    uint_config.assign(1, HybridUintConfig(7, 0, 0));
730
0
    return true;
731
0
  }
732
733
87.0k
  uint_config.assign(clustered_histograms.size(), params.UintConfig());
734
  // If the uint config is fixed, just use it.
735
87.0k
  if (params.uint_method != HistogramParams::HybridUintMethod::kBest &&
736
80.3k
      params.uint_method != HistogramParams::HybridUintMethod::kFast) {
737
65.3k
    return true;
738
65.3k
  }
739
  // Even if the uint config is adaptive, just stick with the default in
740
  // streaming mode.
741
21.6k
  if (params.streaming_mode) {
742
0
    return true;
743
0
  }
744
745
  // Brute-force method that tries a few options.
746
21.6k
  std::vector<HybridUintConfig> configs;
747
21.6k
  if (params.uint_method == HistogramParams::HybridUintMethod::kBest) {
748
6.69k
    configs = {
749
6.69k
        HybridUintConfig(4, 2, 0),  // default
750
6.69k
        HybridUintConfig(4, 1, 0),  // less precise
751
6.69k
        HybridUintConfig(4, 2, 1),  // add sign
752
6.69k
        HybridUintConfig(4, 2, 2),  // add sign+parity
753
6.69k
        HybridUintConfig(4, 1, 2),  // add parity but less msb
754
        // Same as above, but more direct coding.
755
6.69k
        HybridUintConfig(5, 2, 0), HybridUintConfig(5, 1, 0),
756
6.69k
        HybridUintConfig(5, 2, 1), HybridUintConfig(5, 2, 2),
757
6.69k
        HybridUintConfig(5, 1, 2),
758
        // Same as above, but less direct coding.
759
6.69k
        HybridUintConfig(3, 2, 0), HybridUintConfig(3, 1, 0),
760
6.69k
        HybridUintConfig(3, 2, 1), HybridUintConfig(3, 1, 2),
761
        // For near-lossless.
762
6.69k
        HybridUintConfig(4, 1, 3), HybridUintConfig(5, 1, 4),
763
6.69k
        HybridUintConfig(5, 2, 3), HybridUintConfig(6, 1, 5),
764
6.69k
        HybridUintConfig(6, 2, 4), HybridUintConfig(6, 0, 0),
765
        // Other
766
6.69k
        HybridUintConfig(0, 0, 0),   // varlenuint
767
6.69k
        HybridUintConfig(2, 0, 1),   // works well for ctx map
768
6.69k
        HybridUintConfig(7, 0, 0),   // direct coding
769
6.69k
        HybridUintConfig(8, 0, 0),   // direct coding
770
6.69k
        HybridUintConfig(9, 0, 0),   // direct coding
771
6.69k
        HybridUintConfig(10, 0, 0),  // direct coding
772
6.69k
        HybridUintConfig(11, 0, 0),  // direct coding
773
6.69k
        HybridUintConfig(12, 0, 0),  // direct coding
774
6.69k
    };
775
15.0k
  } else {
776
15.0k
    JXL_DASSERT(params.uint_method == HistogramParams::HybridUintMethod::kFast);
777
15.0k
    configs = {
778
15.0k
        HybridUintConfig(4, 2, 0),  // default
779
15.0k
        HybridUintConfig(4, 1, 2),  // add parity but less msb
780
15.0k
        HybridUintConfig(0, 0, 0),  // smallest histograms
781
15.0k
        HybridUintConfig(2, 0, 1),  // works well for ctx map
782
15.0k
    };
783
15.0k
  }
784
785
21.6k
  size_t num_histo = clustered_histograms.size();
786
21.6k
  std::vector<uint8_t> is_valid(num_histo);
787
21.6k
  std::vector<size_t> histo_volume(2 * num_histo);
788
21.6k
  std::vector<size_t> histo_offset(2 * num_histo + 1);
789
21.6k
  std::vector<uint32_t> max_value_per_histo(2 * num_histo);
790
791
  // TODO(veluca): do not ignore lz77 commands.
792
793
185k
  for (const auto& stream : tokens) {
794
70.4M
    for (const auto& token : stream) {
795
70.4M
      size_t histo = context_map[token.context];
796
70.4M
      histo_volume[histo + (token.is_lz77_length ? num_histo : 0)]++;
797
70.4M
    }
798
185k
  }
799
21.6k
  size_t max_histo_volume = 0;
800
233k
  for (size_t h = 0; h < 2 * num_histo; ++h) {
801
211k
    max_histo_volume = std::max(max_histo_volume, histo_volume[h]);
802
211k
    histo_offset[h + 1] = histo_offset[h] + histo_volume[h];
803
211k
  }
804
805
21.6k
  const size_t max_vec_size = MaxVectorSize();
806
21.6k
  std::vector<uint32_t> transposed(histo_offset[num_histo * 2] + max_vec_size);
807
21.6k
  {
808
21.6k
    std::vector<size_t> next_offset = histo_offset;  // copy
809
185k
    for (const auto& stream : tokens) {
810
70.4M
      for (const auto& token : stream) {
811
70.4M
        size_t histo =
812
70.4M
            context_map[token.context] + (token.is_lz77_length ? num_histo : 0);
813
70.4M
        transposed[next_offset[histo]++] = token.value;
814
70.4M
      }
815
185k
    }
816
21.6k
  }
817
233k
  for (size_t h = 0; h < 2 * num_histo; ++h) {
818
211k
    max_value_per_histo[h] =
819
211k
        MaxValue(transposed.data() + histo_offset[h], histo_volume[h]);
820
211k
  }
821
21.6k
  uint32_t max_lz77 = 0;
822
127k
  for (size_t h = num_histo; h < 2 * num_histo; ++h) {
823
105k
    max_lz77 = std::max(max_lz77, MaxValue(transposed.data() + histo_offset[h],
824
105k
                                           histo_volume[h]));
825
105k
  }
826
827
  // Wider histograms are assigned max cost in PopulationCost anyway
828
  // and therefore will not be used
829
21.6k
  size_t max_alpha = ANS_MAX_ALPHABET_SIZE;
830
831
21.6k
  JXL_ASSIGN_OR_RETURN(
832
21.6k
      AlignedMemory tmp,
833
21.6k
      AlignedMemory::Create(memory_manager, (max_histo_volume + max_vec_size) *
834
21.6k
                                                sizeof(uint32_t)));
835
127k
  for (size_t h = 0; h < num_histo; h++) {
836
105k
    float best_cost = std::numeric_limits<float>::max();
837
995k
    for (HybridUintConfig cfg : configs) {
838
995k
      uint32_t max_v = max_value_per_histo[h];
839
995k
      size_t capacity;
840
995k
      {
841
995k
        uint32_t tok, nbits, bits;
842
995k
        cfg.Encode(max_v, &tok, &nbits, &bits);
843
995k
        tok |= cfg.LsbMask();
844
995k
        if (tok >= max_alpha || (lz77.enabled && tok >= lz77.min_symbol)) {
845
37.7k
          continue;  // Not valid config for this context
846
37.7k
        }
847
957k
        capacity = tok + 1;
848
957k
      }
849
850
0
      Histogram histo;
851
957k
      histo.EnsureCapacity(capacity);
852
957k
      size_t len = histo_volume[h];
853
957k
      uint32_t* data = transposed.data() + histo_offset[h];
854
957k
      size_t extra_bits = EstimateTokenCost(data, len, cfg, tmp);
855
957k
      uint32_t* tmp_tokens = tmp.address<uint32_t>();
856
466M
      for (size_t i = 0; i < len; ++i) {
857
465M
        histo.FastAdd(tmp_tokens[i]);
858
465M
      }
859
957k
      histo.Condition();
860
957k
      JXL_ASSIGN_OR_RETURN(float cost, histo.ANSPopulationCost());
861
957k
      cost += extra_bits;
862
      // Add signaling cost of the hybriduintconfig itself.
863
957k
      cost += CeilLog2Nonzero(cfg.split_exponent + 1);
864
957k
      cost += CeilLog2Nonzero(cfg.split_exponent - cfg.msb_in_token + 1);
865
957k
      if (cost < best_cost) {
866
242k
        uint_config[h] = cfg;
867
242k
        best_cost = cost;
868
242k
        clustered_histograms[h].swap(histo);
869
242k
      }
870
957k
    }
871
105k
  }
872
873
21.6k
  size_t max_tok = 0;
874
127k
  for (size_t h = 0; h < num_histo; ++h) {
875
105k
    Histogram& histo = clustered_histograms[h];
876
105k
    max_tok = std::max(max_tok, histo.MaxSymbol());
877
105k
    size_t len = histo_volume[num_histo + h];
878
105k
    if (len == 0) continue;  // E.g. when lz77 not enabled
879
3.51k
    size_t max_histo_tok = max_value_per_histo[num_histo + h];
880
3.51k
    uint32_t tok, nbits, bits;
881
3.51k
    lz77.length_uint_config.Encode(max_histo_tok, &tok, &nbits, &bits);
882
3.51k
    tok |= lz77.length_uint_config.LsbMask();
883
3.51k
    tok += lz77.min_symbol;
884
3.51k
    histo.EnsureCapacity(tok + 1);
885
3.51k
    uint32_t* data = transposed.data() + histo_offset[num_histo + h];
886
3.51k
    uint32_t unused =
887
3.51k
        EstimateTokenCost(data, len, lz77.length_uint_config, tmp);
888
3.51k
    (void)unused;
889
3.51k
    uint32_t* tmp_tokens = tmp.address<uint32_t>();
890
32.2k
    for (size_t i = 0; i < len; ++i) {
891
28.6k
      histo.FastAdd(tmp_tokens[i] + lz77.min_symbol);
892
28.6k
    }
893
3.51k
    histo.Condition();
894
3.51k
    max_tok = std::max(max_tok, histo.MaxSymbol());
895
3.51k
  }
896
897
  // `log_alpha_size - 5` is encoded in the header, so min is 5.
898
21.6k
  size_t log_size = 5;
899
38.0k
  while (max_tok >= (1u << log_size)) ++log_size;
900
901
21.6k
  size_t max_log_alpha_size = use_prefix_code ? PREFIX_MAX_BITS : 8;
902
21.6k
  JXL_ENSURE(log_size <= max_log_alpha_size);
903
904
21.6k
  if (use_prefix_code) {
905
4.30k
    log_alpha_size = PREFIX_MAX_BITS;
906
17.3k
  } else {
907
17.3k
    log_alpha_size = log_size;
908
17.3k
  }
909
910
21.6k
  return true;
911
21.6k
}
912
913
// NOTE: `layer` is only for clustered_entropy; caller does ReclaimAndCharge.
914
// Returns cost (in bits).
915
StatusOr<size_t> EntropyEncodingData::BuildAndStoreEntropyCodes(
916
    JxlMemoryManager* memory_manager, const HistogramParams& params,
917
    const std::vector<std::vector<Token>>& tokens,
918
    const std::vector<Histogram>& builder, BitWriter* writer, LayerType layer,
919
87.0k
    AuxOut* aux_out) {
920
87.0k
  const size_t prev_histograms = encoding_info.size();
921
87.0k
  std::vector<Histogram> clustered_histograms;
922
87.0k
  for (size_t i = 0; i < prev_histograms; ++i) {
923
73
    clustered_histograms.push_back(
924
73
        HistogramFromSymbolInfo(encoding_info[i], use_prefix_code));
925
73
  }
926
87.0k
  size_t context_offset = context_map.size();
927
87.0k
  context_map.resize(context_offset + builder.size());
928
87.0k
  if (builder.size() > 1) {
929
33.4k
    if (!ans_fuzzer_friendly_) {
930
33.4k
      std::vector<uint32_t> histogram_symbols;
931
33.4k
      JXL_RETURN_IF_ERROR(ClusterHistograms(params, builder, kClustersLimit,
932
33.4k
                                            &clustered_histograms,
933
33.4k
                                            &histogram_symbols));
934
32.4M
      for (size_t c = 0; c < builder.size(); ++c) {
935
32.4M
        context_map[context_offset + c] =
936
32.4M
            static_cast<uint8_t>(histogram_symbols[c]);
937
32.4M
      }
938
33.4k
    } else {
939
0
      JXL_ENSURE(encoding_info.empty());
940
0
      std::fill(context_map.begin(), context_map.end(), 0);
941
0
      size_t max_symbol = 0;
942
0
      for (const Histogram& h : builder) {
943
0
        max_symbol = std::max(h.counts.size(), max_symbol);
944
0
      }
945
0
      size_t num_symbols = 1 << CeilLog2Nonzero(max_symbol + 1);
946
0
      clustered_histograms.resize(1);
947
0
      clustered_histograms[0].Clear();
948
0
      for (size_t i = 0; i < num_symbols; i++) {
949
0
        clustered_histograms[0].Add(i);
950
0
      }
951
0
    }
952
33.4k
    if (writer != nullptr) {
953
29.5k
      JXL_RETURN_IF_ERROR(EncodeContextMap(
954
29.5k
          context_map, clustered_histograms.size(), writer, layer, aux_out));
955
29.5k
    }
956
53.5k
  } else {
957
53.5k
    JXL_ENSURE(encoding_info.empty());
958
53.5k
    clustered_histograms.push_back(builder[0]);
959
53.5k
  }
960
87.0k
  if (aux_out != nullptr) {
961
0
    for (size_t i = prev_histograms; i < clustered_histograms.size(); ++i) {
962
0
      aux_out->layer(layer).clustered_entropy +=
963
0
          clustered_histograms[i].ShannonEntropy();
964
0
    }
965
0
  }
966
967
87.0k
  JXL_RETURN_IF_ERROR(
968
87.0k
      ChooseUintConfigs(memory_manager, params, tokens, clustered_histograms));
969
970
87.0k
  SizeWriter size_writer;  // Used if writer == nullptr to estimate costs.
971
87.0k
  size_t cost = use_prefix_code ? 1 : 3;
972
973
87.0k
  if (writer) writer->Write(1, TO_JXL_BOOL(use_prefix_code));
974
87.0k
  if (writer == nullptr) {
975
48.2k
    EncodeUintConfigs(uint_config, &size_writer, log_alpha_size);
976
48.2k
  } else {
977
38.7k
    if (!use_prefix_code) writer->Write(2, log_alpha_size - 5);
978
38.7k
    EncodeUintConfigs(uint_config, writer, log_alpha_size);
979
38.7k
  }
980
87.0k
  if (use_prefix_code) {
981
52.7k
    for (const auto& histo : clustered_histograms) {
982
52.7k
      size_t alphabet_size = std::max<size_t>(1, histo.alphabet_size());
983
52.7k
      if (writer) {
984
12.8k
        StoreVarLenUint16(alphabet_size - 1, writer);
985
39.9k
      } else {
986
39.9k
        StoreVarLenUint16(alphabet_size - 1, &size_writer);
987
39.9k
      }
988
52.7k
    }
989
52.6k
  }
990
87.0k
  cost += size_writer.size;
991
372k
  for (size_t c = prev_histograms; c < clustered_histograms.size(); ++c) {
992
285k
    size_t alphabet_size = clustered_histograms[c].alphabet_size();
993
285k
    encoding_info.emplace_back();
994
285k
    encoding_info.back().resize(alphabet_size);
995
285k
    BitWriter* histo_writer = writer;
996
285k
    if (params.streaming_mode) {
997
1.64k
      encoded_histograms.emplace_back(memory_manager);
998
1.64k
      histo_writer = &encoded_histograms.back();
999
1.64k
    }
1000
285k
    const auto& body = [&]() -> Status {
1001
285k
      JXL_ASSIGN_OR_RETURN(size_t ans_cost,
1002
285k
                           BuildAndStoreANSEncodingData(
1003
285k
                               memory_manager, params.ans_histogram_strategy,
1004
285k
                               clustered_histograms[c], histo_writer));
1005
285k
      cost += ans_cost;
1006
285k
      return true;
1007
285k
    };
1008
285k
    if (histo_writer) {
1009
233k
      JXL_RETURN_IF_ERROR(histo_writer->WithMaxBits(
1010
233k
          256 + alphabet_size * 24, layer, aux_out, body,
1011
233k
          /*finished_histogram=*/true));
1012
233k
    } else {
1013
51.1k
      JXL_RETURN_IF_ERROR(body());
1014
51.1k
    }
1015
285k
    if (params.streaming_mode) {
1016
1.64k
      JXL_RETURN_IF_ERROR(writer->AppendUnaligned(*histo_writer));
1017
1.64k
    }
1018
285k
  }
1019
87.0k
  return cost;
1020
87.0k
}
1021
1022
template <typename Writer>
1023
void EncodeUintConfig(const HybridUintConfig uint_config, Writer* writer,
1024
293k
                      size_t log_alpha_size) {
1025
293k
  writer->Write(CeilLog2Nonzero(log_alpha_size + 1),
1026
293k
                uint_config.split_exponent);
1027
293k
  if (uint_config.split_exponent == log_alpha_size) {
1028
134
    return;  // msb/lsb don't matter.
1029
134
  }
1030
293k
  size_t nbits = CeilLog2Nonzero(uint_config.split_exponent + 1);
1031
293k
  writer->Write(nbits, uint_config.msb_in_token);
1032
293k
  nbits = CeilLog2Nonzero(uint_config.split_exponent -
1033
293k
                          uint_config.msb_in_token + 1);
1034
293k
  writer->Write(nbits, uint_config.lsb_in_token);
1035
293k
}
void jxl::EncodeUintConfig<jxl::SizeWriter>(jxl::HybridUintConfig, jxl::SizeWriter*, unsigned long)
Line
Count
Source
1024
55.0k
                      size_t log_alpha_size) {
1025
55.0k
  writer->Write(CeilLog2Nonzero(log_alpha_size + 1),
1026
55.0k
                uint_config.split_exponent);
1027
55.0k
  if (uint_config.split_exponent == log_alpha_size) {
1028
0
    return;  // msb/lsb don't matter.
1029
0
  }
1030
55.0k
  size_t nbits = CeilLog2Nonzero(uint_config.split_exponent + 1);
1031
55.0k
  writer->Write(nbits, uint_config.msb_in_token);
1032
55.0k
  nbits = CeilLog2Nonzero(uint_config.split_exponent -
1033
55.0k
                          uint_config.msb_in_token + 1);
1034
55.0k
  writer->Write(nbits, uint_config.lsb_in_token);
1035
55.0k
}
void jxl::EncodeUintConfig<jxl::BitWriter>(jxl::HybridUintConfig, jxl::BitWriter*, unsigned long)
Line
Count
Source
1024
238k
                      size_t log_alpha_size) {
1025
238k
  writer->Write(CeilLog2Nonzero(log_alpha_size + 1),
1026
238k
                uint_config.split_exponent);
1027
238k
  if (uint_config.split_exponent == log_alpha_size) {
1028
134
    return;  // msb/lsb don't matter.
1029
134
  }
1030
238k
  size_t nbits = CeilLog2Nonzero(uint_config.split_exponent + 1);
1031
238k
  writer->Write(nbits, uint_config.msb_in_token);
1032
238k
  nbits = CeilLog2Nonzero(uint_config.split_exponent -
1033
238k
                          uint_config.msb_in_token + 1);
1034
238k
  writer->Write(nbits, uint_config.lsb_in_token);
1035
238k
}
1036
template <typename Writer>
1037
void EncodeUintConfigs(const std::vector<HybridUintConfig>& uint_config,
1038
87.0k
                       Writer* writer, size_t log_alpha_size) {
1039
  // TODO(veluca): RLE?
1040
285k
  for (const auto& cfg : uint_config) {
1041
285k
    EncodeUintConfig(cfg, writer, log_alpha_size);
1042
285k
  }
1043
87.0k
}
void jxl::EncodeUintConfigs<jxl::BitWriter>(std::__1::vector<jxl::HybridUintConfig, std::__1::allocator<jxl::HybridUintConfig> > const&, jxl::BitWriter*, unsigned long)
Line
Count
Source
1038
38.8k
                       Writer* writer, size_t log_alpha_size) {
1039
  // TODO(veluca): RLE?
1040
234k
  for (const auto& cfg : uint_config) {
1041
234k
    EncodeUintConfig(cfg, writer, log_alpha_size);
1042
234k
  }
1043
38.8k
}
void jxl::EncodeUintConfigs<jxl::SizeWriter>(std::__1::vector<jxl::HybridUintConfig, std::__1::allocator<jxl::HybridUintConfig> > const&, jxl::SizeWriter*, unsigned long)
Line
Count
Source
1038
48.2k
                       Writer* writer, size_t log_alpha_size) {
1039
  // TODO(veluca): RLE?
1040
51.1k
  for (const auto& cfg : uint_config) {
1041
51.1k
    EncodeUintConfig(cfg, writer, log_alpha_size);
1042
51.1k
  }
1043
48.2k
}
1044
template void EncodeUintConfigs(const std::vector<HybridUintConfig>&,
1045
                                BitWriter*, size_t);
1046
1047
Status EncodeHistograms(const EntropyEncodingData& codes, BitWriter* writer,
1048
73
                        LayerType layer, AuxOut* aux_out) {
1049
73
  return writer->WithMaxBits(
1050
73
      128 + kClustersLimit * 136, layer, aux_out,
1051
73
      [&]() -> Status {
1052
73
        JXL_RETURN_IF_ERROR(Bundle::Write(codes.lz77, writer, layer, aux_out));
1053
73
        if (codes.lz77.enabled) {
1054
0
          EncodeUintConfig(codes.lz77.length_uint_config, writer,
1055
0
                           /*log_alpha_size=*/8);
1056
0
        }
1057
73
        JXL_RETURN_IF_ERROR(EncodeContextMap(codes.context_map,
1058
73
                                             codes.encoding_info.size(), writer,
1059
73
                                             layer, aux_out));
1060
73
        writer->Write(1, TO_JXL_BOOL(codes.use_prefix_code));
1061
73
        size_t log_alpha_size = 8;
1062
73
        if (codes.use_prefix_code) {
1063
48
          log_alpha_size = PREFIX_MAX_BITS;
1064
48
        } else {
1065
25
          log_alpha_size = 8;  // streaming_mode
1066
25
          writer->Write(2, log_alpha_size - 5);
1067
25
        }
1068
73
        EncodeUintConfigs(codes.uint_config, writer, log_alpha_size);
1069
73
        if (codes.use_prefix_code) {
1070
96
          for (const auto& info : codes.encoding_info) {
1071
96
            StoreVarLenUint16(info.size() - 1, writer);
1072
96
          }
1073
48
        }
1074
583
        for (const auto& histo_writer : codes.encoded_histograms) {
1075
583
          JXL_RETURN_IF_ERROR(writer->AppendUnaligned(histo_writer));
1076
583
        }
1077
73
        return true;
1078
73
      },
1079
73
      /*finished_histogram=*/true);
1080
73
}
1081
1082
StatusOr<size_t> BuildAndEncodeHistograms(
1083
    JxlMemoryManager* memory_manager, const HistogramParams& params,
1084
    size_t num_contexts, std::vector<std::vector<Token>>& tokens,
1085
    EntropyEncodingData* codes, BitWriter* writer, LayerType layer,
1086
87.0k
    AuxOut* aux_out) {
1087
  // TODO(Ivan): presumably not needed - default
1088
  // if (params.initialize_global_state) codes->lz77.enabled = false;
1089
87.0k
  codes->lz77.nonserialized_distance_context = num_contexts;
1090
87.0k
  codes->lz77.min_symbol = params.force_huffman ? 512 : 224;
1091
87.0k
  std::vector<std::vector<Token>> tokens_lz77 =
1092
87.0k
      ApplyLZ77(params, num_contexts, tokens, codes->lz77);
1093
87.0k
  if (!tokens_lz77.empty()) codes->lz77.enabled = true;
1094
87.0k
  if (ans_fuzzer_friendly_) {
1095
0
    codes->lz77.length_uint_config = HybridUintConfig(10, 0, 0);
1096
0
    codes->lz77.min_symbol = 2048;
1097
0
  }
1098
1099
87.0k
  size_t cost = 0;
1100
87.0k
  const size_t max_contexts = std::min(num_contexts, kClustersLimit);
1101
87.0k
  const auto& body = [&]() -> Status {
1102
87.0k
    if (writer) {
1103
38.7k
      JXL_RETURN_IF_ERROR(Bundle::Write(codes->lz77, writer, layer, aux_out));
1104
48.2k
    } else {
1105
48.2k
      size_t ebits, bits;
1106
48.2k
      JXL_RETURN_IF_ERROR(Bundle::CanEncode(codes->lz77, &ebits, &bits));
1107
48.2k
      cost += bits;
1108
48.2k
    }
1109
87.0k
    if (codes->lz77.enabled) {
1110
7.88k
      if (writer) {
1111
3.98k
        size_t b = writer->BitsWritten();
1112
3.98k
        EncodeUintConfig(codes->lz77.length_uint_config, writer,
1113
3.98k
                         /*log_alpha_size=*/8);
1114
3.98k
        cost += writer->BitsWritten() - b;
1115
3.98k
      } else {
1116
3.90k
        SizeWriter size_writer;
1117
3.90k
        EncodeUintConfig(codes->lz77.length_uint_config, &size_writer,
1118
3.90k
                         /*log_alpha_size=*/8);
1119
3.90k
        cost += size_writer.size;
1120
3.90k
      }
1121
7.88k
      num_contexts += 1;
1122
7.88k
      JXL_DASSERT(!tokens_lz77.empty());
1123
7.88k
      tokens = std::move(tokens_lz77);
1124
7.88k
    }
1125
87.0k
    size_t total_tokens = 0;
1126
    // Build histograms.
1127
87.0k
    std::vector<Histogram> builder(num_contexts);
1128
87.0k
    HybridUintConfig uint_config = params.UintConfig();
1129
87.0k
    if (ans_fuzzer_friendly_) {
1130
0
      uint_config = HybridUintConfig(10, 0, 0);
1131
0
    }
1132
257k
    for (const auto& stream : tokens) {
1133
257k
      if (codes->lz77.enabled) {
1134
12.6M
        for (const auto& token : stream) {
1135
12.6M
          total_tokens++;
1136
12.6M
          uint32_t tok, nbits, bits;
1137
12.6M
          (token.is_lz77_length ? codes->lz77.length_uint_config : uint_config)
1138
12.6M
              .Encode(token.value, &tok, &nbits, &bits);
1139
12.6M
          tok += token.is_lz77_length ? codes->lz77.min_symbol : 0;
1140
12.6M
          JXL_DASSERT(token.context < num_contexts);
1141
12.6M
          builder[token.context].Add(tok);
1142
12.6M
        }
1143
249k
      } else if (num_contexts == 1) {
1144
40.0M
        for (const auto& token : stream) {
1145
40.0M
          total_tokens++;
1146
40.0M
          uint32_t tok, nbits, bits;
1147
40.0M
          uint_config.Encode(token.value, &tok, &nbits, &bits);
1148
40.0M
          builder[0].Add(tok);
1149
40.0M
        }
1150
194k
      } else {
1151
425M
        for (const auto& token : stream) {
1152
425M
          total_tokens++;
1153
425M
          uint32_t tok, nbits, bits;
1154
425M
          uint_config.Encode(token.value, &tok, &nbits, &bits);
1155
425M
          JXL_DASSERT(token.context < num_contexts);
1156
425M
          builder[token.context].Add(tok);
1157
425M
        }
1158
194k
      }
1159
257k
    }
1160
1161
87.0k
    if (params.add_missing_symbols) {
1162
0
      for (size_t c = 0; c < num_contexts; ++c) {
1163
0
        for (int symbol = 0; symbol < ANS_MAX_ALPHABET_SIZE; ++symbol) {
1164
0
          builder[c].Add(symbol);
1165
0
        }
1166
0
      }
1167
0
    }
1168
1169
87.0k
    if (params.initialize_global_state) {
1170
87.0k
      bool use_prefix_code =
1171
87.0k
          params.force_huffman || total_tokens < 100 ||
1172
34.6k
          params.clustering == HistogramParams::ClusteringType::kFastest ||
1173
34.6k
          ans_fuzzer_friendly_;
1174
87.0k
      if (!use_prefix_code) {
1175
34.6k
        bool all_singleton = true;
1176
29.3M
        for (size_t i = 0; i < num_contexts; i++) {
1177
29.2M
          if (builder[i].ShannonEntropy() >= 1e-5) {
1178
4.13M
            all_singleton = false;
1179
4.13M
          }
1180
29.2M
        }
1181
34.6k
        if (all_singleton) {
1182
279
          use_prefix_code = true;
1183
279
        }
1184
34.6k
      }
1185
87.0k
      codes->use_prefix_code = use_prefix_code;
1186
87.0k
    }
1187
1188
87.0k
    if (params.add_fixed_histograms) {
1189
      // TODO(szabadka) Add more fixed histograms.
1190
      // TODO(szabadka) Reduce alphabet size by choosing a non-default
1191
      // uint_config.
1192
73
      const size_t alphabet_size = ANS_MAX_ALPHABET_SIZE;
1193
73
      codes->log_alpha_size = 8;
1194
73
      JXL_ENSURE(alphabet_size == 1u << codes->log_alpha_size);
1195
73
      static_assert(ANS_MAX_ALPHABET_SIZE <= ANS_TAB_SIZE,
1196
73
                    "Alphabet does not fit table");
1197
73
      codes->encoding_info.emplace_back();
1198
73
      codes->encoding_info.back().resize(alphabet_size);
1199
73
      codes->encoded_histograms.emplace_back(memory_manager);
1200
73
      BitWriter* histo_writer = &codes->encoded_histograms.back();
1201
73
      JXL_RETURN_IF_ERROR(histo_writer->WithMaxBits(
1202
73
          256 + alphabet_size * 24, LayerType::Header, nullptr,
1203
73
          [&]() -> Status {
1204
73
            JXL_ASSIGN_OR_RETURN(
1205
73
                size_t ans_cost,
1206
73
                codes->BuildAndStoreANSEncodingData(
1207
73
                    memory_manager, params.ans_histogram_strategy,
1208
73
                    Histogram::Flat(alphabet_size, ANS_TAB_SIZE),
1209
73
                    histo_writer));
1210
73
            (void)ans_cost;
1211
73
            return true;
1212
73
          }));
1213
73
    }
1214
1215
    // Encode histograms.
1216
87.0k
    JXL_ASSIGN_OR_RETURN(
1217
87.0k
        size_t entropy_bits,
1218
87.0k
        codes->BuildAndStoreEntropyCodes(memory_manager, params, tokens,
1219
87.0k
                                         builder, writer, layer, aux_out));
1220
87.0k
    cost += entropy_bits;
1221
87.0k
    return true;
1222
87.0k
  };
1223
87.0k
  if (writer) {
1224
38.7k
    JXL_RETURN_IF_ERROR(writer->WithMaxBits(
1225
38.7k
        128 + num_contexts * 40 + max_contexts * 96, layer, aux_out, body,
1226
38.7k
        /*finished_histogram=*/true));
1227
48.2k
  } else {
1228
48.2k
    JXL_RETURN_IF_ERROR(body());
1229
48.2k
  }
1230
1231
87.0k
  if (aux_out != nullptr) {
1232
0
    aux_out->layer(layer).num_clustered_histograms +=
1233
0
        codes->encoding_info.size();
1234
0
  }
1235
87.0k
  return cost;
1236
87.0k
}
1237
1238
size_t WriteTokens(const std::vector<Token>& tokens,
1239
                   const EntropyEncodingData& codes, size_t context_offset,
1240
50.9k
                   BitWriter* writer) {
1241
50.9k
  size_t num_extra_bits = 0;
1242
50.9k
  if (codes.use_prefix_code) {
1243
2.08M
    for (const auto& token : tokens) {
1244
2.08M
      uint32_t tok, nbits, bits;
1245
2.08M
      size_t histo = codes.context_map[context_offset + token.context];
1246
2.08M
      (token.is_lz77_length ? codes.lz77.length_uint_config
1247
2.08M
                            : codes.uint_config[histo])
1248
2.08M
          .Encode(token.value, &tok, &nbits, &bits);
1249
2.08M
      tok += token.is_lz77_length ? codes.lz77.min_symbol : 0;
1250
      // Combine two calls to the BitWriter. Equivalent to:
1251
      // writer->Write(codes.encoding_info[histo][tok].depth,
1252
      //               codes.encoding_info[histo][tok].bits);
1253
      // writer->Write(nbits, bits);
1254
2.08M
      uint64_t data = codes.encoding_info[histo][tok].bits;
1255
2.08M
      data |= static_cast<uint64_t>(bits)
1256
2.08M
              << codes.encoding_info[histo][tok].depth;
1257
2.08M
      writer->Write(codes.encoding_info[histo][tok].depth + nbits, data);
1258
2.08M
      num_extra_bits += nbits;
1259
2.08M
    }
1260
14.3k
    return num_extra_bits;
1261
14.3k
  }
1262
36.6k
  std::vector<uint64_t> out;
1263
36.6k
  std::vector<uint8_t> out_nbits;
1264
36.6k
  out.reserve(tokens.size());
1265
36.6k
  out_nbits.reserve(tokens.size());
1266
36.6k
  uint64_t allbits = 0;
1267
36.6k
  size_t numallbits = 0;
1268
  // Writes in *reversed* order.
1269
877M
  auto addbits = [&](size_t bits, size_t nbits) {
1270
877M
    if (JXL_UNLIKELY(nbits)) {
1271
76.5M
      JXL_DASSERT(bits >> nbits == 0);
1272
76.5M
      if (JXL_UNLIKELY(numallbits + nbits > BitWriter::kMaxBitsPerCall)) {
1273
16.4M
        out.push_back(allbits);
1274
16.4M
        out_nbits.push_back(numallbits);
1275
16.4M
        numallbits = allbits = 0;
1276
16.4M
      }
1277
76.5M
      allbits <<= nbits;
1278
76.5M
      allbits |= bits;
1279
76.5M
      numallbits += nbits;
1280
76.5M
    }
1281
877M
  };
1282
36.6k
  const int end = tokens.size();
1283
36.6k
  ANSCoder ans;
1284
36.6k
  if (codes.lz77.enabled || codes.context_map.size() > 1) {
1285
429M
    for (int i = end - 1; i >= 0; --i) {
1286
429M
      const Token token = tokens[i];
1287
429M
      const uint8_t histo = codes.context_map[context_offset + token.context];
1288
429M
      uint32_t tok, nbits, bits;
1289
429M
      (token.is_lz77_length ? codes.lz77.length_uint_config
1290
429M
                            : codes.uint_config[histo])
1291
429M
          .Encode(tokens[i].value, &tok, &nbits, &bits);
1292
429M
      tok += token.is_lz77_length ? codes.lz77.min_symbol : 0;
1293
429M
      const ANSEncSymbolInfo& info = codes.encoding_info[histo][tok];
1294
429M
      JXL_DASSERT(info.freq_ > 0);
1295
      // Extra bits first as this is reversed.
1296
429M
      addbits(bits, nbits);
1297
429M
      num_extra_bits += nbits;
1298
429M
      uint8_t ans_nbits = 0;
1299
429M
      uint32_t ans_bits = ans.PutSymbol(info, &ans_nbits);
1300
429M
      addbits(ans_bits, ans_nbits);
1301
429M
    }
1302
34.9k
  } else {
1303
9.51M
    for (int i = end - 1; i >= 0; --i) {
1304
9.51M
      uint32_t tok, nbits, bits;
1305
9.51M
      codes.uint_config[0].Encode(tokens[i].value, &tok, &nbits, &bits);
1306
9.51M
      const ANSEncSymbolInfo& info = codes.encoding_info[0][tok];
1307
      // Extra bits first as this is reversed.
1308
9.51M
      addbits(bits, nbits);
1309
9.51M
      num_extra_bits += nbits;
1310
9.51M
      uint8_t ans_nbits = 0;
1311
9.51M
      uint32_t ans_bits = ans.PutSymbol(info, &ans_nbits);
1312
9.51M
      addbits(ans_bits, ans_nbits);
1313
9.51M
    }
1314
1.62k
  }
1315
36.6k
  const uint32_t state = ans.GetState();
1316
36.6k
  writer->Write(32, state);
1317
36.6k
  writer->Write(numallbits, allbits);
1318
16.4M
  for (int i = out.size(); i > 0; --i) {
1319
16.4M
    writer->Write(out_nbits[i - 1], out[i - 1]);
1320
16.4M
  }
1321
36.6k
  return num_extra_bits;
1322
36.6k
}
1323
1324
Status WriteTokens(const std::vector<Token>& tokens,
1325
                   const EntropyEncodingData& codes, size_t context_offset,
1326
39.1k
                   BitWriter* writer, LayerType layer, AuxOut* aux_out) {
1327
  // Theoretically, we could have 15 prefix code bits + 31 extra bits.
1328
39.1k
  return writer->WithMaxBits(
1329
39.1k
      46 * tokens.size() + 32 * 1024 * 4, layer, aux_out, [&] {
1330
39.1k
        size_t num_extra_bits =
1331
39.1k
            WriteTokens(tokens, codes, context_offset, writer);
1332
39.1k
        if (aux_out != nullptr) {
1333
0
          aux_out->layer(layer).extra_bits += num_extra_bits;
1334
0
        }
1335
39.1k
        return true;
1336
39.1k
      });
1337
39.1k
}
1338
1339
0
void SetANSFuzzerFriendly(bool ans_fuzzer_friendly) {
1340
#if JXL_IS_DEBUG_BUILD  // Guard against accidental / malicious changes.
1341
0
  ans_fuzzer_friendly_ = ans_fuzzer_friendly;
1342
0
#endif
1343
0
}
1344
1345
HistogramParams HistogramParams::ForModular(
1346
    const CompressParams& cparams,
1347
15.0k
    const std::vector<uint8_t>& extra_dc_precision, bool streaming_mode) {
1348
15.0k
  HistogramParams params;
1349
15.0k
  params.streaming_mode = streaming_mode;
1350
15.0k
  if (cparams.speed_tier > SpeedTier::kKitten) {
1351
15.0k
    params.clustering = HistogramParams::ClusteringType::kFast;
1352
15.0k
    params.ans_histogram_strategy =
1353
15.0k
        cparams.speed_tier > SpeedTier::kThunder
1354
15.0k
            ? HistogramParams::ANSHistogramStrategy::kFast
1355
15.0k
            : HistogramParams::ANSHistogramStrategy::kApproximate;
1356
15.0k
    params.lz77_method =
1357
15.0k
        cparams.modular_mode && cparams.speed_tier <= SpeedTier::kHare
1358
15.0k
            ? HistogramParams::LZ77Method::kRLE
1359
15.0k
            : HistogramParams::LZ77Method::kNone;
1360
    // Near-lossless DC, as well as modular mode, require choosing hybrid uint
1361
    // more carefully.
1362
15.0k
    if ((!extra_dc_precision.empty() && extra_dc_precision[0] != 0) ||
1363
10.1k
        (cparams.modular_mode && cparams.speed_tier < SpeedTier::kCheetah)) {
1364
10.0k
      params.uint_method = HistogramParams::HybridUintMethod::kFast;
1365
10.0k
    } else {
1366
5.00k
      params.uint_method = HistogramParams::HybridUintMethod::kNone;
1367
5.00k
    }
1368
15.0k
  } else if (cparams.speed_tier <= SpeedTier::kTortoise) {
1369
0
    params.lz77_method = HistogramParams::LZ77Method::kOptc256;
1370
0
  } else {
1371
0
    params.lz77_method = HistogramParams::LZ77Method::kLZ77b3w3f;
1372
0
  }
1373
15.0k
  if (cparams.decoding_speed_tier >= 2) {
1374
0
    params.max_histograms = 12;
1375
0
  }
1376
    // No predictor requires LZ77 to compress residuals.
1377
    // Effort 3 and lower have forced predictors, so kNone is set.
1378
15.0k
    if (cparams.options.predictor == Predictor::Zero && cparams.modular_mode) {
1379
0
        params.lz77_method = cparams.speed_tier >= SpeedTier::kFalcon
1380
0
            ? HistogramParams::LZ77Method::kNone
1381
0
            : cparams.speed_tier >= SpeedTier::kHare
1382
0
            ? HistogramParams::LZ77Method::kRLE
1383
0
            : cparams.speed_tier >= SpeedTier::kKitten
1384
0
            ? HistogramParams::LZ77Method::kLZ77b3w3f
1385
0
            : HistogramParams::LZ77Method::kOptc256;
1386
0
    }
1387
15.0k
  return params;
1388
15.0k
}
1389
}  // namespace jxl