KASKADE 7 development version
rangecoder.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the library KASKADE 7 */
4/* https://www.zib.de/research/projects/kaskade7-finite-element-toolbox */
5/* */
6/* Copyright (C) 2002-2015 Zuse Institute Berlin */
7/* */
8/* KASKADE 7 is distributed under the terms of the ZIB Academic License. */
9/* see $KASKADE/academic.txt */
10/* */
11/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13#ifndef RANGECODER_HH
14#define RANGECODER_HH
15
22#include <algorithm>
23#include <cassert>
24#include <exception>
25#include <ios>
26#include <limits>
27#include <numeric>
28#include <vector>
29
30
61template <class UInt>
63{
64protected:
65 // The number of binary digits in our unsigned integral type UInt.
66 static int const digits = std::numeric_limits<UInt>::digits;
67
68 // Mask for shifting of ranges during normalization. All numbers
69 // smaller than top have 8 zero leading bits.
70 //
71 // Smaller value of top, e.g. 1 << digits-16, would allow to shift
72 // the range by a larger amount and output short's instead of char's
73 // for improved performance. A dawback of this is that bottom needs
74 // to be decreased as well, which leads to a small maxRange and
75 // hence a low resolution of the alphabet's probability table.
76 static UInt const top = static_cast<UInt>(1) << (digits-8);
77
78 // The smallest value of range that is possible. The class invariant
79 // is range>=bottom. In contrast to top, the shift of bottom does
80 // not need to be a multiple of 8. Smaller values of bottom lead to
81 // a lower resolution of the alphabet's probability table (and hence
82 // a worse approximation of symbol probabilities, in particular for
83 // very different probabilities), however, it also saves space due
84 // to fewer carry compensations.
85 static UInt const bottom = static_cast<UInt>(1) << (digits-16);
86
87public:
91 static const UInt maxRange = bottom;
92
100 size_t size() const {
101 return count;
102 }
103
104protected:
106 : low(0), range(std::numeric_limits<UInt>::max()), count(0)
107 {
108 assert(std::numeric_limits<UInt>::is_specialized);
109 assert(!std::numeric_limits<UInt>::is_signed);
110 assert(digits > 16);
111 }
112
113 UInt low, range;
114 size_t count;
115};
116
117//---------------------------------------------------------------------
118
134template <class UInt>
135class RangeEncoder:public RangeCoder<UInt>
136{
137 static UInt const bottom = RangeCoder<UInt>::bottom;
138 static UInt const top = RangeCoder<UInt>::top;
139 static UInt const digits = RangeCoder<UInt>::digits;
140
141public:
143
144 RangeEncoder(std::ostream& out_)
145 : out(out_), fill(0)
146 {}
147
152 for(int i=0; i<digits/8; i++)
153 put();
154 out.write((char const*)buf,fill);
155 }
156
168 void push(std::pair<UInt,UInt> s, UInt totalRange)
169 {
170 // Check parameters.
171 assert(s.first<s.second);
172 assert(totalRange <= maxRange);
173
174 UInt& range = this->range;
175 UInt& low = this->low;
176
177 // Check class invariant
178 assert(range >= bottom);
180
181
182 range /= totalRange;
183 low += s.first*range;
184 range *= s.second-s.first;
185
186 // Perform range normalization
187 while ( (low^(low+range)) < top
188 || (range<bottom && ((range= -low & (bottom-1)),true)) )
189 put(); // Output of highest byte and shifting of range
190
191 // Check class invariant
192 assert(range >= bottom);
194 }
195
196private:
197 std::ostream& out;
198
199 // Putting one char at a time into the std::ostream is quite
200 // inefficient. We store the bytes in a small buffer and feed the
201 // buffer into the ostream once it is full. A buffer size of 64
202 // seems to be a good compromise between performance improvement and
203 // memory consumption.
204 static int const bufsize = 64;
205 unsigned char buf[bufsize];
206 int fill;
207
208 void put() {
209 UInt& range = this->range;
210 UInt& low = this->low;
211
212 if (fill==bufsize) {
213 out.write((char const*)buf,bufsize);
214 if (!out)
215 throw std::ios_base::failure("write error");
216 fill = 0;
217 this->count += bufsize;
218 }
219
220 // Store eight most significant bits (top) in stream buffer.
221 buf[fill] = low >> (digits-8);
222 ++fill;
223
224 // shift window
225 range <<= 8;
226 low <<= 8;
227 }
228};
229
230//---------------------------------------------------------------------
231
243template <class UInt>
244class RangeDecoder:public RangeCoder<UInt>
245{
246 static UInt const bottom = RangeCoder<UInt>::bottom;
247 static UInt const top = RangeCoder<UInt>::top;
248 static UInt const digits = RangeCoder<UInt>::digits;
249
250 UInt code;
251 std::istream& in;
252
253public:
255
261 RangeDecoder(std::istream& input_)
262 : code(0), in(input_)
263 {
264 // Throw ios_base::failure if end of stream is reached.
265 in.exceptions(std::ios_base::eofbit | in.exceptions());
266
267 // Fill range
268 for(int i=0; i<digits/8; i++) {
269 code = (code << 8) | in.get();
270 if (!in) throw std::ios_base::failure("read error");
271 ++this->count;
272 }
273 }
274
282 UInt front(UInt totalRange) const {
283 UInt const& range = this->range;
284 UInt const& low = this->low;
285
286 return (code-low)/(range/totalRange);
287 }
288
307 void pop(std::pair<UInt,UInt> s, UInt totalRange) {
308 UInt& range = this->range;
309 UInt& low = this->low;
310
311 assert(s.first<=front(totalRange)
312 && front(totalRange)<s.second);
313
314 range /= totalRange;
315 low += s.first*range;
316 range *= s.second-s.first;
317
318 // Perform range normalization
319 while ( (low^(low+range))<top
320 || (range<bottom && ((range= -low & (bottom-1)),true)) ) {
321 code = code<<8 | in.get();
322 range <<= 8;
323 low <<= 8;
324 ++this->count;
325 }
326 }
327};
328
329
330//---------------------------------------------------------------------
331//---------------------------------------------------------------------
332
341template <class UInt>
342class Alphabet {
343public:
349 template <class InIter>
350 Alphabet(InIter first, InIter last)
351 : cumFreq(std::distance(first,last)+1)
352 {
353 cumFreq[0] = 0;
354 std::partial_sum(first,last,cumFreq.begin()+1,std::plus<UInt>());
355 }
356
364 template <class InIter>
365 void update(InIter first, InIter last)
366 {
367 assert(std::distance(first,last)==size()); // check that all symbols are covered
368 assert(std::find(first,last,0)==last); // check that all frequencies are greater than zero
369 std::partial_sum(first,last,cumFreq.begin()+1,std::plus<UInt>()); // compute cumulative distribution
370 }
371
375 UInt totalRange() const
376 {
377 return cumFreq.back();
378 }
379
383 UInt size() const
384 {
385 return cumFreq.size()-1;
386 }
387
391 UInt symbol(UInt value) const
392 {
393 typename std::vector<UInt>::const_iterator i
394 = std::upper_bound(cumFreq.begin(),cumFreq.end(), value);
395 assert(i==cumFreq.end() || *i>value);
396 assert(i!=cumFreq.begin());
397 return i-cumFreq.begin()-1;
398 }
399
403 std::pair<UInt,UInt> range(UInt symbol) const
404 {
405 assert(symbol<size());
406 return std::make_pair(cumFreq[symbol],cumFreq[symbol+1]);
407 }
408
409
410private:
411 // cumulated frequencies for the symbols
412 std::vector<UInt> cumFreq;
413};
414
415//---------------------------------------------------------------------
416//---------------------------------------------------------------------
417
423template <class UInt, class Symbol>
424void encodeSymbol(RangeEncoder<UInt>& encoder, Alphabet<UInt> const& alphabet,
425 Symbol const& s) {
426 encoder.push(alphabet.range(s),alphabet.totalRange());
427}
428
429
435template <class UInt>
436UInt decodeSymbol(RangeDecoder<UInt>& decoder, Alphabet<UInt> const& alphabet) {
437 UInt s = alphabet.symbol(decoder.front(alphabet.totalRange()));
438 decoder.pop(alphabet.range(s),alphabet.totalRange());
439 return s;
440}
441
442//---------------------------------------------------------------------
443//---------------------------------------------------------------------
444
445
446
447#endif
A simple alphabet of symbols with frequencies to be used with the range coder.
Definition: rangecoder.hh:342
UInt totalRange() const
Returns the total range, i.e. the maximum upper range bound of any symbol in the alphabet.
Definition: rangecoder.hh:375
Alphabet(InIter first, InIter last)
Definition: rangecoder.hh:350
UInt symbol(UInt value) const
Returns the symbol that contains the given value.
Definition: rangecoder.hh:391
UInt size() const
Returns the number of symbols in the alphabet.
Definition: rangecoder.hh:383
void update(InIter first, InIter last)
Modifies the symbols' half-open ranges to represent the symbols' frequencies given in the range [firs...
Definition: rangecoder.hh:365
std::pair< UInt, UInt > range(UInt symbol) const
Returns the symbol's half-open cumulative frequency range.
Definition: rangecoder.hh:403
Base class for entropy coding with range encoder and decoder.
Definition: rangecoder.hh:63
static int const digits
Definition: rangecoder.hh:66
static const UInt maxRange
Maximal total range of alphabets.
Definition: rangecoder.hh:91
size_t size() const
Number of processed encoded bytes.
Definition: rangecoder.hh:100
size_t count
Definition: rangecoder.hh:114
static UInt const bottom
Definition: rangecoder.hh:85
static UInt const top
Definition: rangecoder.hh:76
Entropy coding with range decoder.
Definition: rangecoder.hh:245
RangeDecoder(std::istream &input_)
Definition: rangecoder.hh:261
static UInt const maxRange
Definition: rangecoder.hh:254
void pop(std::pair< UInt, UInt > s, UInt totalRange)
Definition: rangecoder.hh:307
UInt front(UInt totalRange) const
Definition: rangecoder.hh:282
Entropy coding with range encoder.
Definition: rangecoder.hh:136
RangeEncoder(std::ostream &out_)
Definition: rangecoder.hh:144
static UInt const maxRange
Definition: rangecoder.hh:142
~RangeEncoder()
Destructor writes the remaining data to the output stream.
Definition: rangecoder.hh:151
void push(std::pair< UInt, UInt > s, UInt totalRange)
Encodes one symbol.
Definition: rangecoder.hh:168
UInt decodeSymbol(RangeDecoder< UInt > &decoder, Alphabet< UInt > const &alphabet)
A convenience function that retrieves and pops the current symbol from a range decoder.
Definition: rangecoder.hh:436
void encodeSymbol(RangeEncoder< UInt > &encoder, Alphabet< UInt > const &alphabet, Symbol const &s)
A convenience function that encodes a symbol in a range encoder.
Definition: rangecoder.hh:424
Dune::FieldVector< T, n > max(Dune::FieldVector< T, n > x, Dune::FieldVector< T, n > const &y)
Componentwise maximum.
Definition: fixdune.hh:110
Scalar distance(Point< Scalar, dim > const &first, Point< Scalar, dim > const &second)