DCCL v5
Loading...
Searching...
No Matches
field_codec_arithmetic.cpp
1// Copyright 2012-2023:
2// GobySoft, LLC (2013-)
3// Massachusetts Institute of Technology (2007-2014)
4// Community contributors (see AUTHORS file)
5// File authors:
6// Toby Schneider <toby@gobysoft.org>
7//
8//
9// This file is part of the Dynamic Compact Control Language Library
10// ("DCCL").
11//
12// DCCL is free software: you can redistribute it and/or modify
13// it under the terms of the GNU Lesser General Public License as published by
14// the Free Software Foundation, either version 2.1 of the License, or
15// (at your option) any later version.
16//
17// DCCL is distributed in the hope that it will be useful,
18// but WITHOUT ANY WARRANTY; without even the implied warranty of
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20// GNU Lesser General Public License for more details.
21//
22// You should have received a copy of the GNU Lesser General Public License
23// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
24#include "field_codec_arithmetic.h"
25#include "../codec.h"
26
27using dccl::dlog;
28using namespace dccl::logger;
29
30const dccl::arith::Model::symbol_type dccl::arith::Model::OUT_OF_RANGE_SYMBOL;
31const dccl::arith::Model::symbol_type dccl::arith::Model::EOF_SYMBOL;
32const dccl::arith::Model::symbol_type dccl::arith::Model::MIN_SYMBOL;
33const int dccl::arith::Model::CODE_VALUE_BITS;
34const int dccl::arith::Model::FREQUENCY_BITS;
35const dccl::arith::Model::freq_type dccl::arith::Model::MAX_FREQUENCY;
36
37#if DCCL_THREAD_SUPPORT
38std::recursive_mutex dccl::arith::Model::last_bits_map_mutex;
39#endif
40std::map<std::string, std::map<std::string, dccl::Bitset>> dccl::arith::Model::last_bits_map;
41
42// shared library load
43extern "C"
44{
45 void dccl3_load(dccl::Codec* dccl) { dccl_arithmetic_load(dccl); }
46
47 void dccl_arithmetic_load(dccl::Codec* dccl)
48 {
49 using namespace dccl;
50 using namespace dccl::arith;
51
52 dccl->manager().add<ArithmeticFieldCodec<int32>>("_arithmetic");
53 dccl->manager().add<ArithmeticFieldCodec<int64>>("_arithmetic");
54 dccl->manager().add<ArithmeticFieldCodec<uint32>>("_arithmetic");
55 dccl->manager().add<ArithmeticFieldCodec<uint64>>("_arithmetic");
56 dccl->manager().add<ArithmeticFieldCodec<double>>("_arithmetic");
57 dccl->manager().add<ArithmeticFieldCodec<float>>("_arithmetic");
58 dccl->manager().add<ArithmeticFieldCodec<bool>>("_arithmetic");
60 "_arithmetic");
61
62 dccl->manager().add<ArithmeticFieldCodec<int32>>("dccl.arithmetic");
63 dccl->manager().add<ArithmeticFieldCodec<int64>>("dccl.arithmetic");
64 dccl->manager().add<ArithmeticFieldCodec<uint32>>("dccl.arithmetic");
65 dccl->manager().add<ArithmeticFieldCodec<uint64>>("dccl.arithmetic");
66 dccl->manager().add<ArithmeticFieldCodec<double>>("dccl.arithmetic");
67 dccl->manager().add<ArithmeticFieldCodec<float>>("dccl.arithmetic");
68 dccl->manager().add<ArithmeticFieldCodec<bool>>("dccl.arithmetic");
70 "dccl.arithmetic");
71 }
72 void dccl3_unload(dccl::Codec* dccl) { dccl_arithmetic_unload(dccl); }
73
74 void dccl_arithmetic_unload(dccl::Codec* dccl)
75 {
76 using namespace dccl;
77 using namespace dccl::arith;
78
79 dccl->manager().remove<ArithmeticFieldCodec<int32>>("_arithmetic");
80 dccl->manager().remove<ArithmeticFieldCodec<int64>>("_arithmetic");
81 dccl->manager().remove<ArithmeticFieldCodec<uint32>>("_arithmetic");
82 dccl->manager().remove<ArithmeticFieldCodec<uint64>>("_arithmetic");
83 dccl->manager().remove<ArithmeticFieldCodec<double>>("_arithmetic");
84 dccl->manager().remove<ArithmeticFieldCodec<float>>("_arithmetic");
85 dccl->manager().remove<ArithmeticFieldCodec<bool>>("_arithmetic");
87 "_arithmetic");
88
89 dccl->manager().remove<ArithmeticFieldCodec<int32>>("dccl.arithmetic");
90 dccl->manager().remove<ArithmeticFieldCodec<int64>>("dccl.arithmetic");
91 dccl->manager().remove<ArithmeticFieldCodec<uint32>>("dccl.arithmetic");
92 dccl->manager().remove<ArithmeticFieldCodec<uint64>>("dccl.arithmetic");
93 dccl->manager().remove<ArithmeticFieldCodec<double>>("dccl.arithmetic");
94 dccl->manager().remove<ArithmeticFieldCodec<float>>("dccl.arithmetic");
95 dccl->manager().remove<ArithmeticFieldCodec<bool>>("dccl.arithmetic");
97 "dccl.arithmetic");
98 }
99}
100
101dccl::arith::Model::symbol_type dccl::arith::Model::value_to_symbol(value_type value) const
102{
103 if (value < *user_model_.value_bound().begin() ||
104 value > *(user_model_.value_bound().end() - 1))
105 return Model::OUT_OF_RANGE_SYMBOL;
106
107 google::protobuf::RepeatedField<double>::const_iterator upper_it =
108 std::upper_bound(user_model_.value_bound().begin(), user_model_.value_bound().end(), value);
109
110 google::protobuf::RepeatedField<double>::const_iterator lower_it =
111 (upper_it == user_model_.value_bound().begin()) ? upper_it : upper_it - 1;
112
113 double lower_diff = std::abs((*lower_it) * (*lower_it) - value * value);
114 double upper_diff = std::abs((*upper_it) * (*upper_it) - value * value);
115
116 // std::cout << "value: " << value << std::endl;
117 // std::cout << "lower_value: " << *lower_it << std::endl;
118 // std::cout << "upper_value: " << *upper_it << std::endl;
119
120 symbol_type symbol =
121 ((lower_diff < upper_diff) ? lower_it : upper_it) - user_model_.value_bound().begin();
122
123 return symbol;
124}
125
126dccl::arith::Model::value_type dccl::arith::Model::symbol_to_value(symbol_type symbol) const
127{
128 if (symbol == EOF_SYMBOL)
129 throw(Exception("EOF symbol has no value."));
130
131 value_type value = (symbol == Model::OUT_OF_RANGE_SYMBOL)
132 ? std::numeric_limits<value_type>::quiet_NaN()
133 : user_model_.value_bound(symbol);
134
135 return value;
136}
137
138std::pair<dccl::arith::Model::freq_type, dccl::arith::Model::freq_type>
139dccl::arith::Model::symbol_to_cumulative_freq(symbol_type symbol, ModelState state) const
140{
141 const auto& c_freqs =
142 (state == ENCODER) ? encoder_cumulative_freqs_ : decoder_cumulative_freqs_;
143
144 auto c_freq_it = c_freqs.find(symbol);
145 std::pair<freq_type, freq_type> c_freq_range;
146 c_freq_range.second = c_freq_it->second;
147 if (c_freq_it == c_freqs.begin())
148 {
149 c_freq_range.first = 0;
150 }
151 else
152 {
153 c_freq_it--;
154 c_freq_range.first = c_freq_it->second;
155 }
156 return c_freq_range;
157}
158
159std::pair<dccl::arith::Model::symbol_type, dccl::arith::Model::symbol_type>
160dccl::arith::Model::cumulative_freq_to_symbol(std::pair<freq_type, freq_type> c_freq_pair,
161 ModelState state) const
162{
163 const auto& c_freqs =
164 (state == ENCODER) ? encoder_cumulative_freqs_ : decoder_cumulative_freqs_;
165
166 std::pair<symbol_type, symbol_type> symbol_pair;
167
168 // find the symbol for which the cumulative frequency is greater than
169 // e.g.
170 // symbol: 0 freq: 10 c_freq: 10 [0 ... 10)
171 // symbol: 1 freq: 15 c_freq: 25 [10 ... 25)
172 // symbol: 2 freq: 10 c_freq: 35 [25 ... 35)
173 // searching for c_freq of 30 should return symbol 2
174 // searching for c_freq of 10 should return symbol 1
175 auto search = c_freq_pair.first;
176 for (const auto& p : c_freqs)
177 {
178 if (search < p.second)
179 {
180 symbol_pair.first = p.first;
181 break;
182 }
183 }
184
185 if (symbol_pair.first == c_freqs.rbegin()->first)
186 symbol_pair.second = symbol_pair.first; // last symbol can't be ambiguous on the low end
187 else if (c_freqs.find(symbol_pair.first)->second > c_freq_pair.second)
188 symbol_pair.second = symbol_pair.first; // unambiguously this symbol
189 else
190 symbol_pair.second = symbol_pair.first + 1;
191
192 return symbol_pair;
193}
194
195void dccl::arith::Model::update_model(symbol_type symbol, ModelState state)
196{
197 if (!user_model_.is_adaptive())
198 return;
199
200 auto& c_freqs = (state == ENCODER) ? encoder_cumulative_freqs_ : decoder_cumulative_freqs_;
201
202 if (dlog.check(DEBUG3))
203 {
204 dlog.is(DEBUG3) && dlog << "Model was: " << std::endl;
205 for (symbol_type i = MIN_SYMBOL, n = max_symbol(); i <= n; ++i)
206 {
207 auto it = c_freqs.find(i);
208 if (it != c_freqs.end())
209 dlog.is(DEBUG3) && dlog << "Symbol: " << it->first << ", c_freq: " << it->second
210 << std::endl;
211 }
212 }
213
214 for (symbol_type i = max_symbol(), n = symbol; i >= n; --i)
215 {
216 auto it = c_freqs.find(i);
217 if (it != c_freqs.end())
218 ++it->second;
219 }
220
221 if (dlog.check(DEBUG3))
222 {
223 dlog.is(DEBUG3) && dlog << "Model is now: " << std::endl;
224 for (symbol_type i = MIN_SYMBOL, n = max_symbol(); i <= n; ++i)
225 {
226 auto it = c_freqs.find(i);
227 if (it != c_freqs.end())
228 dlog.is(DEBUG3) && dlog << "Symbol: " << it->first << ", c_freq: " << it->second
229 << std::endl;
230 }
231 }
232
233 dlog.is(DEBUG3) && dlog << "total freq: " << total_freq(state) << std::endl;
234}
235
236void dccl::arith::ModelManager::set_model(dccl::Codec& codec,
237 const protobuf::ArithmeticModel& model)
238{
239 model_manager(codec.manager())._set_model(model);
240}
241
242dccl::arith::ModelManager& dccl::arith::model_manager(FieldCodecManagerLocal& manager)
243{
244 if (!manager.codec_data().template has_codec_specific_data<ArithmeticFieldCodecBase<>>())
245 {
246 auto model_manager = std::make_shared<dccl::any>(ModelManager());
247 manager.codec_data().template set_codec_specific_data<ArithmeticFieldCodecBase<>>(
248 model_manager);
249 }
250 return dccl::any_cast<ModelManager&>(
251 *manager.codec_data().template codec_specific_data<ArithmeticFieldCodecBase<>>());
252}
The Dynamic CCL enCODer/DECoder. This is the main class you will use to load, encode and decode DCCL ...
Definition codec.h:61
Exception class for DCCL.
Definition exception.h:47
A class for managing the various field codecs. Here you can add and remove field codecs....
bool is(logger::Verbosity verbosity, logger::Group group=logger::GENERAL)
Indicates the verbosity of the Logger until the next std::flush or std::endl. The boolean return is u...
Definition logger.h:191
bool check(logger::Verbosity verbosity)
Same as is() but doesn't set the verbosity or lock the mutex.
Definition logger.h:180
DCCL Arithmetic Encoder Library namespace.
Dynamic Compact Control Language namespace.
Definition any.h:28