64 using symbol_type = int;
65 using value_type = double;
67 static constexpr symbol_type OUT_OF_RANGE_SYMBOL = -1;
68 static constexpr symbol_type EOF_SYMBOL = -2;
69 static constexpr symbol_type MIN_SYMBOL = EOF_SYMBOL;
71 static constexpr int CODE_VALUE_BITS = 32;
72 static constexpr int FREQUENCY_BITS = CODE_VALUE_BITS - 2;
74 static constexpr freq_type MAX_FREQUENCY = (1 << FREQUENCY_BITS) - 1;
76#if DCCL_THREAD_SUPPORT
77 static std::recursive_mutex last_bits_map_mutex;
78#define LOCK_LAST_BITS_MAP_MUTEX \
79 std::lock_guard<std::recursive_mutex> l(dccl::arith::Model::last_bits_map_mutex);
81#define LOCK_LAST_BITS_MAP_MUTEX
84 static std::map<std::string, std::map<std::string, Bitset>> last_bits_map;
94 symbol_type value_to_symbol(value_type value)
const;
95 value_type symbol_to_value(symbol_type symbol)
const;
96 symbol_type total_symbols()
98 return encoder_cumulative_freqs_.size();
103 symbol_type max_symbol()
const {
return user_model_.frequency_size() - 1; }
105 freq_type total_freq(ModelState state)
const
107 const auto& c_freqs =
108 (state == ENCODER) ? encoder_cumulative_freqs_ : decoder_cumulative_freqs_;
110 return c_freqs.at(max_symbol());
113 void update_model(symbol_type symbol, ModelState state);
115 std::pair<freq_type, freq_type> symbol_to_cumulative_freq(symbol_type symbol,
116 ModelState state)
const;
117 std::pair<symbol_type, symbol_type>
118 cumulative_freq_to_symbol(std::pair<freq_type, freq_type> c_freq_pair, ModelState state)
const;
124 std::map<symbol_type, freq_type> encoder_cumulative_freqs_;
125 std::map<symbol_type, freq_type> decoder_cumulative_freqs_;
133 Model& find(
const std::string& name)
135 auto it = arithmetic_models_.find(name);
136 if (it == arithmetic_models_.end())
137 throw(
Exception(
"Cannot find model called: " + name));
145 Model new_model(model);
146 _create_and_validate_model(&new_model);
147 if (arithmetic_models_.count(model.name()))
148 arithmetic_models_.erase(model.name());
149 arithmetic_models_.emplace(model.name(), new_model);
152 void _create_and_validate_model(
Model* model)
154 if (!model->user_model_.IsInitialized())
156 throw(
Exception(
"Invalid model: " + model->user_model_.DebugString() +
157 "Missing fields: " + model->user_model_.InitializationErrorString()));
160 Model::freq_type cumulative_freq = 0;
161 for (Model::symbol_type symbol = Model::MIN_SYMBOL, n = model->user_model_.frequency_size();
162 symbol < n; ++symbol)
164 Model::freq_type freq;
165 if (symbol == Model::EOF_SYMBOL)
166 freq = model->user_model_.eof_frequency();
167 else if (symbol == Model::OUT_OF_RANGE_SYMBOL)
168 freq = model->user_model_.out_of_range_frequency();
170 freq = model->user_model_.frequency(symbol);
172 if (freq == 0 && symbol != Model::OUT_OF_RANGE_SYMBOL && symbol != Model::EOF_SYMBOL)
174 throw(
Exception(
"Invalid model: " + model->user_model_.DebugString() +
175 "All frequencies must be nonzero."));
177 cumulative_freq += freq;
178 model->encoder_cumulative_freqs_.emplace(symbol, cumulative_freq);
182 model->decoder_cumulative_freqs_ = model->encoder_cumulative_freqs_;
184 if (model->total_freq(Model::ENCODER) > Model::MAX_FREQUENCY)
186 throw(
Exception(
"Invalid model: " + model->user_model_.DebugString() +
187 "Sum of all frequencies must be less than " +
188 std::to_string(Model::MAX_FREQUENCY) +
189 " in order to use 64 bit arithmetic"));
192 if (model->user_model_.value_bound_size() != model->user_model_.frequency_size() + 1)
194 throw(
Exception(
"Invalid model: " + model->user_model_.DebugString() +
195 "`value_bound` size must be exactly 1 more than number of symbols (= "
196 "size of `frequency`)."));
200 if (std::adjacent_find(
201 model->user_model_.value_bound().begin(), model->user_model_.value_bound().end(),
202 std::greater_equal<Model::value_type>()) != model->user_model_.value_bound().end())
204 throw(
Exception(
"Invalid model: " + model->user_model_.DebugString() +
205 "`value_bound` must be monotonically increasing."));
210 std::map<std::string, Model> arithmetic_models_;
217 static constexpr uint64 TOP_VALUE =
218 (
static_cast<uint64>(1) << Model::CODE_VALUE_BITS) - 1;
219 static constexpr uint64 HALF =
220 (
static_cast<uint64>(1) << (Model::CODE_VALUE_BITS - 1));
221 static constexpr uint64 FIRST_QTR = HALF >> 1;
222 static constexpr uint64 THIRD_QTR = HALF + FIRST_QTR;
224 Bitset encode_repeated(
const std::vector<Model::value_type>& wire_value)
override
226 return encode_repeated(wire_value,
true);
229 Bitset encode_repeated(
const std::vector<Model::value_type>& wire_value,
bool update_model)
232 using namespace dccl::logger;
233 Model& model = current_model();
237 int bits_to_follow = 0;
240 for (
unsigned value_index = 0, n = max_repeat(); value_index < n; ++value_index)
242 Model::symbol_type symbol = Model::EOF_SYMBOL;
244 if (wire_value.size() > value_index)
246 Model::value_type value = wire_value[value_index];
247 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec) value is : " << value
250 symbol = model.value_to_symbol(value);
254 if (symbol == Model::OUT_OF_RANGE_SYMBOL &&
255 model.user_model().out_of_range_frequency() == 0)
257 dlog.
is(DEBUG2) && dlog <<
"(ArithmeticFieldCodec) out of range symbol, but no "
258 "frequency given; ending encoding"
261 symbol = Model::EOF_SYMBOL;
265 if (symbol == Model::EOF_SYMBOL && model.user_model().eof_frequency() == 0)
267 dlog.
is(DEBUG2) && dlog <<
"(ArithmeticFieldCodec) end of file, but no frequency "
268 "given; filling with most probable symbol"
270 symbol = *std::max_element(model.user_model().frequency().begin(),
271 model.user_model().frequency().end());
274 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec) symbol is : " << symbol << std::endl;
276 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec) current interval: ["
277 << (double)low / TOP_VALUE <<
"," << (
double)high / TOP_VALUE
280 uint64 range = (high - low) + 1;
282 auto [c_freq_low, c_freq_high] = model.symbol_to_cumulative_freq(symbol, Model::ENCODER);
284 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec) input symbol (" << symbol
285 <<
") cumulative freq: [" << c_freq_low <<
","
286 << c_freq_high <<
")" << std::endl;
288 high = low + (range * c_freq_high) / model.total_freq(Model::ENCODER) - 1;
289 low += (range * c_freq_low) / model.total_freq(Model::ENCODER);
291 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec) input symbol (" << symbol
292 <<
") interval: [" << (double)low / TOP_VALUE <<
","
293 << (
double)high / TOP_VALUE <<
")" << std::endl;
296 dlog <<
"(ArithmeticFieldCodec) Q1: " <<
Bitset(Model::CODE_VALUE_BITS, FIRST_QTR)
297 <<
", Q2: " <<
Bitset(Model::CODE_VALUE_BITS, HALF)
298 <<
", Q3 : " <<
Bitset(Model::CODE_VALUE_BITS, THIRD_QTR)
299 <<
", top: " <<
Bitset(Model::CODE_VALUE_BITS, TOP_VALUE) << std::endl;
301 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec) low: "
303 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec) high: "
308 model.update_model(symbol, Model::ENCODER);
314 bit_plus_follow(&bits, &bits_to_follow, 0);
316 dlog <<
"(ArithmeticFieldCodec): completely in [0, 0.5): EXPAND"
319 else if (low >= HALF)
321 bit_plus_follow(&bits, &bits_to_follow, 1);
325 dlog <<
"(ArithmeticFieldCodec): completely in [0.5, 1): EXPAND"
328 else if (low >= FIRST_QTR && high < THIRD_QTR)
331 dlog <<
"(ArithmeticFieldCodec): straddle middle [0.25, 0.75): EXPAND"
345 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec) low: "
348 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec) high: "
352 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec) current interval: ["
353 << (double)low / TOP_VALUE <<
","
354 << (
double)high / TOP_VALUE <<
")" << std::endl;
358 if (value_index == wire_value.size())
369 if (high != TOP_VALUE || bits_to_follow > 0)
370 bit_plus_follow(&bits, &bits_to_follow, 0);
374 else if (high == TOP_VALUE)
376 bit_plus_follow(&bits, &bits_to_follow, 1);
384 bit_plus_follow(&bits, &bits_to_follow, (low < FIRST_QTR) ? 0 : 1);
389 LOCK_LAST_BITS_MAP_MUTEX
398 void bit_plus_follow(
Bitset* bits,
int* bits_to_follow,
bool bit)
400 bits->push_back(bit);
401 dccl::dlog.
is(dccl::logger::DEBUG3) &&
402 dccl::dlog <<
"(ArithmeticFieldCodec): emitted bit: " << bit << std::endl;
404 while (*bits_to_follow)
406 dccl::dlog.
is(dccl::logger::DEBUG3) &&
407 dccl::dlog <<
"(ArithmeticFieldCodec): emitted bit (from follow): " << !bit
410 bits->push_back(!bit);
411 (*bits_to_follow) -= 1;
418 using namespace dccl::logger;
420 std::vector<Model::value_type> values;
421 Model& model = current_model();
429 int bit_stream_offset = Model::CODE_VALUE_BITS - bits->size();
431 for (
int i = 0, n = Model::CODE_VALUE_BITS; i < n; ++i)
433 if (i >= bit_stream_offset)
435 (
static_cast<uint64>((*bits)[bits->size() - (i - bit_stream_offset) - 1]) << i);
438 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec): starting value: "
441 for (
unsigned value_index = 0, n = max_repeat(); value_index < n; ++value_index)
443 uint64 range = (high - low) + 1;
445 Model::symbol_type symbol = bits_to_symbol(bits, value, bit_stream_offset, low, range);
447 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec) symbol is: " << symbol << std::endl;
449 auto [c_freq_low, c_freq_high] = model.symbol_to_cumulative_freq(symbol, Model::DECODER);
451 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec) input symbol (" << symbol
452 <<
") cumulative freq: [" << c_freq_low <<
","
453 << c_freq_high <<
")" << std::endl;
455 high = low + (range * c_freq_high) / model.total_freq(Model::DECODER) - 1;
456 low += (range * c_freq_low) / model.total_freq(Model::DECODER);
458 model.update_model(symbol, Model::DECODER);
460 if (symbol == Model::EOF_SYMBOL)
463 values.push_back(model.symbol_to_value(symbol));
465 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec) value is: " << values.back()
474 else if (low >= HALF)
480 else if (low >= FIRST_QTR && high < THIRD_QTR)
493 bit_stream_offset += 1;
500 LOCK_LAST_BITS_MAP_MUTEX
506 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec) bits used is (" << bits->size()
507 <<
"): " << *bits << std::endl;
508 dlog.
is(DEBUG3) && dlog <<
"(ArithmeticFieldCodec) bits original is (" << in.size()
509 <<
"): " << in << std::endl;
517 unsigned size_repeated(
const std::vector<Model::value_type>& wire_values)
override
520 return encode_repeated(wire_values,
false).size();
528 Model& model = current_model();
532 Model::freq_type out_of_range_freq = model.user_model().out_of_range_frequency();
533 if (out_of_range_freq == 0)
534 out_of_range_freq = Model::MAX_FREQUENCY;
536 Model::value_type lowest_frequency =
537 std::min(out_of_range_freq, *std::min_element(model.user_model().frequency().begin(),
538 model.user_model().frequency().end()));
541 auto size_least_probable = (unsigned)(std::ceil(
542 max_repeat() * (log2(model.total_freq(Model::ENCODER)) - log2(lowest_frequency))));
544 dccl::dlog.
is(dccl::logger::DEBUG3) &&
545 dccl::dlog <<
"(ArithmeticFieldCodec) size_least_probable: " << size_least_probable
548 Model::freq_type eof_freq = model.user_model().eof_frequency();
550 auto size_least_probable_plus_eof =
551 (unsigned)((eof_freq != 0)
552 ? std::ceil(max_repeat() * log2(model.total_freq(Model::ENCODER)) -
553 (max_repeat() - 1) * log2(lowest_frequency) - log2(eof_freq))
556 dccl::dlog.
is(dccl::logger::DEBUG3) &&
557 dccl::dlog <<
"(ArithmeticFieldCodec) size_least_probable_plus_eof: "
558 << size_least_probable_plus_eof << std::endl;
560 return std::max(size_least_probable_plus_eof, size_least_probable) + 1;
566 const Model& model = current_model();
568 if (model.user_model().is_adaptive())
573 Model::freq_type out_of_range_freq = model.user_model().out_of_range_frequency();
574 if (out_of_range_freq == 0)
575 out_of_range_freq = 1;
577 Model::freq_type eof_freq = model.user_model().eof_frequency();
580 (unsigned)((eof_freq != 0)
581 ? std::ceil(log2(model.total_freq(Model::ENCODER)) - log2(eof_freq))
582 : std::numeric_limits<unsigned>::max());
584 dccl::dlog.
is(dccl::logger::DEBUG3) &&
585 dccl::dlog <<
"(ArithmeticFieldCodec) size_empty: " << size_empty << std::endl;
588 Model::value_type highest_frequency =
589 std::max(out_of_range_freq, *std::max_element(model.user_model().frequency().begin(),
590 model.user_model().frequency().end()));
592 auto size_most_probable = (unsigned)(std::ceil(
593 max_repeat() * (log2(model.total_freq(Model::ENCODER)) - log2(highest_frequency))));
595 dccl::dlog.
is(dccl::logger::DEBUG3) &&
596 dccl::dlog <<
"(ArithmeticFieldCodec) size_most_probable: " << size_most_probable
599 return std::min(size_empty, size_most_probable);
605 "missing (dccl.field).arithmetic");
607 std::string model_name =
611 model_manager().find(model_name);
616 model_name +
"\" loaded.");
622 Model::symbol_type bits_to_symbol(
Bitset* bits,
uint64& value,
int& bit_stream_offset,
625 Model& model = current_model();
629 uint64 value_high = (bit_stream_offset > 0)
630 ? value + ((
static_cast<uint64>(1) << bit_stream_offset) - 1)
633 dccl::dlog.
is(dccl::logger::DEBUG3) &&
634 dccl::dlog <<
"(ArithmeticFieldCodec): value range: ["
635 <<
Bitset(Model::CODE_VALUE_BITS, value) <<
","
636 <<
Bitset(Model::CODE_VALUE_BITS, value_high) <<
")" << std::endl;
638 Model::freq_type cumulative_freq =
639 ((value - low + 1) * model.total_freq(Model::DECODER) - 1) / range;
640 Model::freq_type cumulative_freq_high =
641 ((value_high - low + 1) * model.total_freq(Model::DECODER) - 1) / range;
643 dccl::dlog.
is(dccl::logger::DEBUG3) &&
644 dccl::dlog <<
"(ArithmeticFieldCodec): c_freq: " << cumulative_freq
645 <<
", c_freq_high: " << cumulative_freq_high << std::endl;
647 auto [symbol_low, symbol_high] =
648 model.cumulative_freq_to_symbol({cumulative_freq, cumulative_freq_high},
651 dccl::dlog.
is(dccl::logger::DEBUG3) &&
652 dccl::dlog <<
"(ArithmeticFieldCodec): symbol: " << symbol_low <<
", "
653 << symbol_high << std::endl;
655 if (symbol_low == symbol_high)
661 dccl::dlog.
is(dccl::logger::DEBUG3) &&
662 dccl::dlog <<
"(ArithmeticFieldCodec): bits: " << *bits << std::endl;
665 value |=
static_cast<uint64>(bits->back()) << bit_stream_offset;
667 dccl::dlog.
is(dccl::logger::DEBUG3) &&
668 dccl::dlog <<
"(ArithmeticFieldCodec): ambiguous (symbol could be "
669 << symbol_low <<
" or " << symbol_high <<
")" << std::endl;
682 Model& current_model()
685 return model_manager().find(
name);
688 ModelManager& model_manager() {
return dccl::arith::model_manager(this->manager()); }