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