DCCL v4
field_codec_arithmetic.cpp
1 // Copyright 2012-2017:
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 
25 #include "field_codec_arithmetic.h"
26 #include "../codec.h"
27 #include "../field_codec_manager.h"
28 
29 using dccl::dlog;
30 using namespace dccl::logger;
31 
32 const dccl::arith::Model::symbol_type dccl::arith::Model::OUT_OF_RANGE_SYMBOL;
33 const dccl::arith::Model::symbol_type dccl::arith::Model::EOF_SYMBOL;
34 const dccl::arith::Model::symbol_type dccl::arith::Model::MIN_SYMBOL;
35 const int dccl::arith::Model::CODE_VALUE_BITS;
36 const int dccl::arith::Model::FREQUENCY_BITS;
37 const dccl::arith::Model::freq_type dccl::arith::Model::MAX_FREQUENCY;
38 
39 #if DCCL_THREAD_SUPPORT
40 std::recursive_mutex dccl::arith::Model::last_bits_map_mutex;
41 #endif
42 std::map<std::string, std::map<std::string, dccl::Bitset>> dccl::arith::Model::last_bits_map;
43 
44 // shared library load
45 extern "C"
46 {
47  void dccl3_load(dccl::Codec* dccl) { dccl_arithmetic_load(dccl); }
48 
49  void dccl_arithmetic_load(dccl::Codec* dccl)
50  {
51  using namespace dccl;
52  using namespace dccl::arith;
53 
54  dccl->manager().add<ArithmeticFieldCodec<int32>>("_arithmetic");
55  dccl->manager().add<ArithmeticFieldCodec<int64>>("_arithmetic");
56  dccl->manager().add<ArithmeticFieldCodec<uint32>>("_arithmetic");
57  dccl->manager().add<ArithmeticFieldCodec<uint64>>("_arithmetic");
58  dccl->manager().add<ArithmeticFieldCodec<double>>("_arithmetic");
59  dccl->manager().add<ArithmeticFieldCodec<float>>("_arithmetic");
60  dccl->manager().add<ArithmeticFieldCodec<bool>>("_arithmetic");
62  "_arithmetic");
63 
64  dccl->manager().add<ArithmeticFieldCodec<int32>>("dccl.arithmetic");
65  dccl->manager().add<ArithmeticFieldCodec<int64>>("dccl.arithmetic");
66  dccl->manager().add<ArithmeticFieldCodec<uint32>>("dccl.arithmetic");
67  dccl->manager().add<ArithmeticFieldCodec<uint64>>("dccl.arithmetic");
68  dccl->manager().add<ArithmeticFieldCodec<double>>("dccl.arithmetic");
69  dccl->manager().add<ArithmeticFieldCodec<float>>("dccl.arithmetic");
70  dccl->manager().add<ArithmeticFieldCodec<bool>>("dccl.arithmetic");
72  "dccl.arithmetic");
73  }
74  void dccl3_unload(dccl::Codec* dccl) { dccl_arithmetic_unload(dccl); }
75 
76  void dccl_arithmetic_unload(dccl::Codec* dccl)
77  {
78  using namespace dccl;
79  using namespace dccl::arith;
80 
81  dccl->manager().remove<ArithmeticFieldCodec<int32>>("_arithmetic");
82  dccl->manager().remove<ArithmeticFieldCodec<int64>>("_arithmetic");
83  dccl->manager().remove<ArithmeticFieldCodec<uint32>>("_arithmetic");
84  dccl->manager().remove<ArithmeticFieldCodec<uint64>>("_arithmetic");
85  dccl->manager().remove<ArithmeticFieldCodec<double>>("_arithmetic");
86  dccl->manager().remove<ArithmeticFieldCodec<float>>("_arithmetic");
87  dccl->manager().remove<ArithmeticFieldCodec<bool>>("_arithmetic");
89  "_arithmetic");
90 
91  dccl->manager().remove<ArithmeticFieldCodec<int32>>("dccl.arithmetic");
92  dccl->manager().remove<ArithmeticFieldCodec<int64>>("dccl.arithmetic");
93  dccl->manager().remove<ArithmeticFieldCodec<uint32>>("dccl.arithmetic");
94  dccl->manager().remove<ArithmeticFieldCodec<uint64>>("dccl.arithmetic");
95  dccl->manager().remove<ArithmeticFieldCodec<double>>("dccl.arithmetic");
96  dccl->manager().remove<ArithmeticFieldCodec<float>>("dccl.arithmetic");
97  dccl->manager().remove<ArithmeticFieldCodec<bool>>("dccl.arithmetic");
99  "dccl.arithmetic");
100  }
101 }
102 
103 dccl::arith::Model::symbol_type dccl::arith::Model::value_to_symbol(value_type value) const
104 {
105  if (value < *user_model_.value_bound().begin() ||
106  value > *(user_model_.value_bound().end() - 1))
107  return Model::OUT_OF_RANGE_SYMBOL;
108 
109  google::protobuf::RepeatedField<double>::const_iterator upper_it =
110  std::upper_bound(user_model_.value_bound().begin(), user_model_.value_bound().end(), value);
111 
112  google::protobuf::RepeatedField<double>::const_iterator lower_it =
113  (upper_it == user_model_.value_bound().begin()) ? upper_it : upper_it - 1;
114 
115  double lower_diff = std::abs((*lower_it) * (*lower_it) - value * value);
116  double upper_diff = std::abs((*upper_it) * (*upper_it) - value * value);
117 
118  // std::cout << "value: " << value << std::endl;
119  // std::cout << "lower_value: " << *lower_it << std::endl;
120  // std::cout << "upper_value: " << *upper_it << std::endl;
121 
122  symbol_type symbol =
123  ((lower_diff < upper_diff) ? lower_it : upper_it) - user_model_.value_bound().begin();
124 
125  return symbol;
126 }
127 
128 dccl::arith::Model::value_type dccl::arith::Model::symbol_to_value(symbol_type symbol) const
129 {
130  if (symbol == EOF_SYMBOL)
131  throw(Exception("EOF symbol has no value."));
132 
133  value_type value = (symbol == Model::OUT_OF_RANGE_SYMBOL)
134  ? std::numeric_limits<value_type>::quiet_NaN()
135  : user_model_.value_bound(symbol);
136 
137  return value;
138 }
139 
140 std::pair<dccl::arith::Model::freq_type, dccl::arith::Model::freq_type>
141 dccl::arith::Model::symbol_to_cumulative_freq(symbol_type symbol, ModelState state) const
142 {
143  const auto& c_freqs =
144  (state == ENCODER) ? encoder_cumulative_freqs_ : decoder_cumulative_freqs_;
145 
146  auto c_freq_it = c_freqs.find(symbol);
147  std::pair<freq_type, freq_type> c_freq_range;
148  c_freq_range.second = c_freq_it->second;
149  if (c_freq_it == c_freqs.begin())
150  {
151  c_freq_range.first = 0;
152  }
153  else
154  {
155  c_freq_it--;
156  c_freq_range.first = c_freq_it->second;
157  }
158  return c_freq_range;
159 }
160 
161 std::pair<dccl::arith::Model::symbol_type, dccl::arith::Model::symbol_type>
162 dccl::arith::Model::cumulative_freq_to_symbol(std::pair<freq_type, freq_type> c_freq_pair,
163  ModelState state) const
164 {
165  const auto& c_freqs =
166  (state == ENCODER) ? encoder_cumulative_freqs_ : decoder_cumulative_freqs_;
167 
168  std::pair<symbol_type, symbol_type> symbol_pair;
169 
170  // find the symbol for which the cumulative frequency is greater than
171  // e.g.
172  // symbol: 0 freq: 10 c_freq: 10 [0 ... 10)
173  // symbol: 1 freq: 15 c_freq: 25 [10 ... 25)
174  // symbol: 2 freq: 10 c_freq: 35 [25 ... 35)
175  // searching for c_freq of 30 should return symbol 2
176  // searching for c_freq of 10 should return symbol 1
177  auto search = c_freq_pair.first;
178  for (const auto& p : c_freqs)
179  {
180  if (search < p.second)
181  {
182  symbol_pair.first = p.first;
183  break;
184  }
185  }
186 
187  if (symbol_pair.first == c_freqs.rbegin()->first)
188  symbol_pair.second = symbol_pair.first; // last symbol can't be ambiguous on the low end
189  else if (c_freqs.find(symbol_pair.first)->second > c_freq_pair.second)
190  symbol_pair.second = symbol_pair.first; // unambiguously this symbol
191  else
192  symbol_pair.second = symbol_pair.first + 1;
193 
194  return symbol_pair;
195 }
196 
197 void dccl::arith::Model::update_model(symbol_type symbol, ModelState state)
198 {
199  if (!user_model_.is_adaptive())
200  return;
201 
202  auto& c_freqs = (state == ENCODER) ? encoder_cumulative_freqs_ : decoder_cumulative_freqs_;
203 
204  if (dlog.check(DEBUG3))
205  {
206  dlog.is(DEBUG3) && dlog << "Model was: " << std::endl;
207  for (symbol_type i = MIN_SYMBOL, n = max_symbol(); i <= n; ++i)
208  {
209  auto it = c_freqs.find(i);
210  if (it != c_freqs.end())
211  dlog.is(DEBUG3) && dlog << "Symbol: " << it->first << ", c_freq: " << it->second
212  << std::endl;
213  }
214  }
215 
216  for (symbol_type i = max_symbol(), n = symbol; i >= n; --i)
217  {
218  auto it = c_freqs.find(i);
219  if (it != c_freqs.end())
220  ++it->second;
221  }
222 
223  if (dlog.check(DEBUG3))
224  {
225  dlog.is(DEBUG3) && dlog << "Model is now: " << std::endl;
226  for (symbol_type i = MIN_SYMBOL, n = max_symbol(); i <= n; ++i)
227  {
228  auto it = c_freqs.find(i);
229  if (it != c_freqs.end())
230  dlog.is(DEBUG3) && dlog << "Symbol: " << it->first << ", c_freq: " << it->second
231  << std::endl;
232  }
233  }
234 
235  dlog.is(DEBUG3) && dlog << "total freq: " << total_freq(state) << std::endl;
236 }
237 
238 void dccl::arith::ModelManager::set_model(dccl::Codec& codec,
239  const protobuf::ArithmeticModel& model)
240 {
241  model_manager(codec.manager())._set_model(model);
242 }
243 
244 dccl::arith::ModelManager& dccl::arith::model_manager(FieldCodecManagerLocal& manager)
245 {
246  if (!manager.codec_data().template has_codec_specific_data<ArithmeticFieldCodecBase<>>())
247  {
248  auto model_manager = std::make_shared<dccl::any>(ModelManager());
249  manager.codec_data().template set_codec_specific_data<ArithmeticFieldCodecBase<>>(
250  model_manager);
251  }
252  return dccl::any_cast<ModelManager&>(
253  *manager.codec_data().template codec_specific_data<ArithmeticFieldCodecBase<>>());
254 }
dccl::FieldCodecManagerLocal
A class for managing the various field codecs. Here you can add and remove field codecs....
Definition: field_codec_manager.h:39
dccl::arith::ArithmeticFieldCodecBase
Definition: field_codec_arithmetic.h:214
dccl
Dynamic Compact Control Language namespace.
Definition: any.h:49
dccl::Logger::is
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:192
dccl::Exception
Exception class for DCCL.
Definition: exception.h:47
dccl::arith::ModelManager
Definition: field_codec_arithmetic.h:128
dccl::Codec
The Dynamic CCL enCODer/DECoder. This is the main class you will use to load, encode and decode DCCL ...
Definition: codec.h:62
dccl::arith::ArithmeticFieldCodec< const google::protobuf::EnumValueDescriptor * >
Definition: field_codec_arithmetic.h:713
dccl::Logger::check
bool check(logger::Verbosity verbosity)
Same as is() but doesn't set the verbosity or lock the mutex.
Definition: logger.h:181
dccl::arith::protobuf::ArithmeticModel
Definition: arithmetic.pb.h:73
dccl::arith::ArithmeticFieldCodec
Definition: field_codec_arithmetic.h:699
dccl::arith
DCCL Arithmetic Encoder Library namespace.
Definition: field_codec_arithmetic.h:54