Goby v2
test.cpp
1 // Copyright 2009-2018 Toby Schneider (http://gobysoft.org/index.wt/people/toby)
2 // GobySoft, LLC (2013-)
3 // Massachusetts Institute of Technology (2007-2014)
4 //
5 //
6 // This file is part of the Goby Underwater Autonomy Project Binaries
7 // ("The Goby Binaries").
8 //
9 // The Goby Binaries are free software: you can redistribute them and/or modify
10 // them under the terms of the GNU General Public License as published by
11 // the Free Software Foundation, either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // The Goby Binaries are distributed in the hope that they will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Goby. If not, see <http://www.gnu.org/licenses/>.
21 
22 // tests arithmetic encoder
23 
24 #include <google/protobuf/descriptor.pb.h>
25 
26 #include "dccl/arithmetic/field_codec_arithmetic.h"
27 #include "goby/acomms/dccl.h"
28 
29 #include "goby/common/time.h"
30 #include "goby/util/as.h"
31 #include "goby/util/binary.h"
32 #include "test.pb.h"
33 
34 using goby::acomms::operator<<;
35 
36 void run_test(dccl::arith::protobuf::ArithmeticModel& model,
37  const google::protobuf::Message& msg_in, bool set_model = true)
38 {
40 
41  void* dl_handle = dlopen("libdccl_arithmetic" SHARED_LIBRARY_SUFFIX, RTLD_LAZY);
42 
43  if (!dl_handle)
44  {
45  std::cerr << "Failed to open libdccl_arithmetic" SHARED_LIBRARY_SUFFIX << std::endl;
46  exit(1);
47  }
48  codec->load_shared_library_codecs(dl_handle);
49 
50  if (set_model)
51  {
52  model.set_name("model");
53  dccl::arith::ModelManager::set_model(model);
54  }
55 
56  codec->info(msg_in.GetDescriptor(), &std::cout);
57 
58  codec->validate(msg_in.GetDescriptor());
59 
60  std::cout << "Message in:\n" << msg_in.DebugString() << std::endl;
61 
62  std::cout << "Try encode..." << std::endl;
63  std::string bytes;
64  codec->encode(&bytes, msg_in);
65  std::cout << "... got bytes (hex): " << goby::util::hex_encode(bytes) << std::endl;
66 
67  std::cout << "Try decode..." << std::endl;
68 
69  boost::shared_ptr<google::protobuf::Message> msg_out(msg_in.New());
70  codec->decode(bytes, msg_out.get());
71 
72  std::cout << "... got Message out:\n" << msg_out->DebugString() << std::endl;
73 
74  assert(msg_in.SerializeAsString() == msg_out->SerializeAsString());
75 }
76 
77 // usage: goby_test_dccl10 [boolean: verbose]
78 int main(int argc, char* argv[])
79 {
80  if (argc > 1 && goby::util::as<bool>(argv[1]) == 1)
81  goby::glog.add_stream(goby::common::logger::DEBUG3, &std::cerr);
82  else
83  goby::glog.add_stream(goby::common::logger::DEBUG2, &std::cerr);
84  goby::glog.set_name(argv[0]);
85 
88  codec->set_cfg(cfg);
89 
90  // test case from Practical Implementations of Arithmetic Coding by Paul G. Howard and Je rey Scott Vitter
91  {
92  dccl::arith::protobuf::ArithmeticModel model;
93 
94  model.set_eof_frequency(4); // "a"
95 
96  model.add_value_bound(0);
97  model.add_frequency(5); // "b"
98 
99  model.add_value_bound(1);
100  model.add_frequency(1); // "EOF"
101 
102  model.add_value_bound(2);
103 
104  model.set_out_of_range_frequency(0);
105 
107 
108  msg_in.add_value(0); // b
109  msg_in.add_value(0); // b
110  msg_in.add_value(0); // b
111  msg_in.add_value(1); // "EOF"
112 
113  run_test(model, msg_in);
114  }
115 
116  // misc test case
117  {
118  dccl::arith::protobuf::ArithmeticModel model;
119 
120  model.add_value_bound(100.0);
121  model.add_frequency(100);
122 
123  model.add_value_bound(100.1);
124  model.add_frequency(100);
125 
126  model.add_value_bound(100.2);
127  model.add_frequency(100);
128 
129  model.add_value_bound(100.3);
130  model.add_frequency(100);
131 
132  model.add_value_bound(100.4);
133  model.add_frequency(90);
134 
135  model.add_value_bound(100.5);
136  model.add_frequency(125);
137 
138  model.add_value_bound(100.6);
139  model.add_frequency(125);
140 
141  model.add_value_bound(100.7);
142  model.add_frequency(125);
143 
144  model.add_value_bound(100.8);
145 
146  model.set_eof_frequency(25);
147  model.set_out_of_range_frequency(10);
148 
150 
151  msg_in.add_value(100.5);
152  msg_in.add_value(100.7);
153  msg_in.add_value(100.2);
154 
155  run_test(model, msg_in);
156  }
157 
158  // edge case 1, should be just a single bit ("1")
159  {
160  dccl::arith::protobuf::ArithmeticModel model;
161 
162  model.set_eof_frequency(10);
163  model.set_out_of_range_frequency(0);
164 
165  model.add_value_bound(1);
166  model.add_frequency(2);
167 
168  model.add_value_bound(2);
169  model.add_frequency(3);
170 
171  model.add_value_bound(3);
172  model.add_frequency(85);
173 
174  model.add_value_bound(4);
175 
176  ArithmeticEnumTestMsg msg_in;
177 
178  msg_in.add_value(ENUM_C);
179  msg_in.add_value(ENUM_C);
180  msg_in.add_value(ENUM_C);
181  msg_in.add_value(ENUM_C);
182 
183  run_test(model, msg_in);
184  }
185 
186  // edge case 2, should be full 23 or 24 bits
187  {
188  dccl::arith::protobuf::ArithmeticModel model;
189 
190  model.set_eof_frequency(10);
191  model.set_out_of_range_frequency(0);
192 
193  model.add_value_bound(1);
194  model.add_frequency(2);
195 
196  model.add_value_bound(2);
197  model.add_frequency(3);
198 
199  model.add_value_bound(3);
200  model.add_frequency(85);
201 
202  model.add_value_bound(4);
203 
204  ArithmeticEnumTestMsg msg_in;
205 
206  msg_in.add_value(ENUM_A);
207  msg_in.add_value(ENUM_A);
208  msg_in.add_value(ENUM_A);
209  msg_in.add_value(ENUM_A);
210 
211  run_test(model, msg_in);
212  }
213 
214  {
215  dccl::arith::protobuf::ArithmeticModel model;
216 
217  model.set_eof_frequency(10);
218  model.set_out_of_range_frequency(0);
219 
220  model.add_value_bound(1);
221  model.add_frequency(2);
222 
223  model.add_value_bound(2);
224  model.add_frequency(3);
225 
226  model.add_value_bound(3);
227  model.add_frequency(85);
228 
229  model.add_value_bound(4);
230 
232 
233  msg_in.set_value(ENUM_B);
234 
235  run_test(model, msg_in);
236  }
237 
238  // test case from Practical Implementations of Arithmetic Coding by Paul G. Howard and Je rey Scott Vitter
239  {
240  dccl::arith::protobuf::ArithmeticModel model;
241 
242  model.set_eof_frequency(1);
243 
244  model.add_value_bound(0);
245  model.add_frequency(1);
246 
247  model.add_value_bound(1);
248  model.add_frequency(1);
249 
250  model.add_value_bound(2);
251 
252  model.set_out_of_range_frequency(1);
253 
255 
256  msg_in.add_value(0);
257  msg_in.add_value(0);
258  msg_in.add_value(0);
259  msg_in.add_value(1);
260 
261  model.set_is_adaptive(true);
262  run_test(model, msg_in);
263  run_test(model, msg_in, false);
264  run_test(model, msg_in, false);
265  run_test(model, msg_in, false);
266  }
267 
268  // test case from Arithmetic Coding revealed: A guided tour from theory to praxis Sable Technical Report No. 2007-5 Eric Bodden
269 
270  {
271  dccl::arith::protobuf::ArithmeticModel model;
272 
273  model.set_eof_frequency(0);
274  model.set_out_of_range_frequency(0);
275 
276  model.add_value_bound(1);
277  model.add_frequency(2);
278 
279  model.add_value_bound(2);
280  model.add_frequency(1);
281 
282  model.add_value_bound(3);
283  model.add_frequency(3);
284 
285  model.add_value_bound(4);
286  model.add_frequency(1);
287 
288  model.add_value_bound(5);
289  model.add_frequency(1);
290 
291  model.add_value_bound(6);
292 
293  ArithmeticEnum2TestMsg msg_in;
294 
295  msg_in.add_value(ENUM2_A);
296  msg_in.add_value(ENUM2_B);
297  msg_in.add_value(ENUM2_C);
298  msg_in.add_value(ENUM2_C);
299  msg_in.add_value(ENUM2_E);
300  msg_in.add_value(ENUM2_D);
301  msg_in.add_value(ENUM2_A);
302  msg_in.add_value(ENUM2_C);
303 
304  run_test(model, msg_in);
305  }
306 
307  // randomly generate a model and a message
308  // loop over all message lengths from 0 to 100
309  srand(time(NULL));
310  for (unsigned i = 0; i <= ArithmeticDouble2TestMsg::descriptor()
311  ->FindFieldByName("value")
312  ->options()
313  .GetExtension(dccl::field)
314  .max_repeat();
315  ++i)
316  {
317  dccl::arith::protobuf::ArithmeticModel model;
318 
319  // pick some endpoints
320  goby::int32 low = -(rand() % std::numeric_limits<goby::int32>::max());
321  goby::int32 high = rand() % std::numeric_limits<goby::int32>::max();
322 
323  std::cout << "low: " << low << ", high: " << high << std::endl;
324 
325  // number of symbols
326  goby::int32 symbols = rand() % 1000 + 10;
327 
328  std::cout << "symbols: " << symbols << std::endl;
329 
330  // maximum freq
331  dccl::arith::Model::freq_type each_max_freq =
332  dccl::arith::Model::MAX_FREQUENCY / (symbols + 2);
333  std::cout << "each_max_freq: " << each_max_freq << std::endl;
334 
335  model.set_eof_frequency(rand() % each_max_freq + 1);
336  model.set_out_of_range_frequency(rand() % each_max_freq + 1);
337 
338  model.add_value_bound(low);
339  model.add_frequency(rand() % each_max_freq + 1);
340  for (int j = 1; j < symbols; ++j)
341  {
342  // std::cout << "j: " << j << std::endl;
343 
344  goby::int32 remaining_range = high - model.value_bound(j - 1);
345  model.add_value_bound(model.value_bound(j - 1) +
346  rand() % (remaining_range / symbols - j) + 1);
347  model.add_frequency(rand() % each_max_freq + 1);
348  }
349 
350  model.add_value_bound(high);
351 
353 
354  for (unsigned j = 0; j < i; ++j) msg_in.add_value(model.value_bound(rand() % symbols));
355 
356  run_test(model, msg_in);
357 
358  std::cout << "end random test #" << i << std::endl;
359  }
360 
361  std::cout << "all tests passed" << std::endl;
362 }
void set_name(const std::string &s)
Set the name of the application that the logger is serving.
Definition: flex_ostream.h:67
static DCCLCodec * get()
DCCLCodec is a singleton class; use this to get a pointer to the class.
Definition: dccl.h:124
common::FlexOstream glog
Access the Goby logger through this object.
void add_stream(logger::Verbosity verbosity=logger::VERBOSE, std::ostream *os=0)
Attach a stream object (e.g. std::cout, std::ofstream, ...) to the logger with desired verbosity...
Definition: flex_ostream.h:96
google::protobuf::int32 int32
a signed 32 bit integer