// Copyright (C) 2004 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_3_
#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_3_
#include "../algs.h"
#include "entropy_encoder_model_kernel_abstract.h"
#include "../assert.h"
namespace dlib
{
template <
unsigned long alphabet_size,
typename entropy_encoder,
typename cc,
typename cc_high
>
class entropy_encoder_model_kernel_3
{
/*!
REQUIREMENTS ON cc
cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h
cc::get_alphabet_size() == alphabet_size+1
REQUIREMENTS ON cc_high
cc_high is an implementation of conditioning_class/conditioning_class_kernel_abstract.h
cc_high::get_alphabet_size() == alphabet_size+1
INITIAL VALUE
- Initially this object's finite context model is empty
- previous_symbol == 0
- previous_symbol2 == 0
- order_1 == pointer to an array of alphabet_size elements
- order_2 == pointer to an array of alphabet_size*alphabet_size elements
- order_2[i] == 0
CONVENTION
&get_entropy_encoder() == coder
&order_0.get_global_state() == &gs
&order_1[i]->get_global_state() == &gs
if (order_2[i] != 0) then
&order_2[i]->get_global_state() == &gs_high
This is an order-2-1-0 model. The last symbol in the order-2, order-1 and
order-0 contexts is an escape into the lower context.
previous_symbol == the last symbol seen
previous_symbol2 == the symbol we saw before previous_symbol
!*/
public:
typedef entropy_encoder entropy_encoder_type;
entropy_encoder_model_kernel_3 (
entropy_encoder& coder
);
virtual ~entropy_encoder_model_kernel_3 (
);
inline void clear(
);
inline void encode (
unsigned long symbol
);
entropy_encoder& get_entropy_encoder (
) { return coder; }
static unsigned long get_alphabet_size (
) { return alphabet_size; }
private:
entropy_encoder& coder;
typename cc::global_state_type gs;
typename cc_high::global_state_type gs_high;
cc order_0;
cc** order_1;
unsigned long previous_symbol;
cc_high** order_2;
unsigned long previous_symbol2;
// restricted functions
entropy_encoder_model_kernel_3(entropy_encoder_model_kernel_3&); // copy constructor
entropy_encoder_model_kernel_3& operator=(entropy_encoder_model_kernel_3&); // assignment operator
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
typename entropy_encoder,
typename cc,
typename cc_high
>
entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc,cc_high>::
entropy_encoder_model_kernel_3 (
entropy_encoder& coder_
) :
coder(coder_),
order_0(gs),
order_1(0),
previous_symbol(0),
order_2(0),
previous_symbol2(0)
{
COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );
try
{
order_1 = new cc*[alphabet_size];
order_2 = new cc_high*[alphabet_size*alphabet_size];
}
catch (...)
{
if (order_1) delete [] order_1;
if (order_2) delete [] order_2;
throw;
}
unsigned long i;
for (i = 0; i < (alphabet_size*alphabet_size); ++i)
{
order_2[i] = 0;
}
try
{
for (i = 0; i < alphabet_size; ++i)
{
order_1[i] = new cc(gs);
}
}
catch (...)
{
for (unsigned long j = 0; j < i; ++j)
{
delete order_1[j];
}
throw;
}
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
typename entropy_encoder,
typename cc,
typename cc_high
>
entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc,cc_high>::
~entropy_encoder_model_kernel_3 (
)
{
for (unsigned long i = 0; i < alphabet_size; ++i)
{
delete order_1[i];
}
for (unsigned long i = 0; i < alphabet_size*alphabet_size; ++i)
{
if (order_2[i] != 0)
delete order_2[i];
}
delete [] order_1;
delete [] order_2;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
typename entropy_encoder,
typename cc,
typename cc_high
>
void entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc,cc_high>::
clear(
)
{
previous_symbol = 0;
previous_symbol2 = 0;
order_0.clear();
for (unsigned long i = 0; i < alphabet_size; ++i)
{
order_1[i]->clear();
}
for (unsigned long i = 0; i < alphabet_size*alphabet_size; ++i)
{
if (order_2[i] != 0)
{
delete order_2[i];
order_2[i] = 0;
}
}
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
typename entropy_encoder,
typename cc,
typename cc_high
>
void entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc,cc_high>::
encode (
unsigned long symbol
)
{
unsigned long low_count = 0, high_count = 0, total_count = 0;
// order-2 context stuff
{
unsigned long temp = previous_symbol + (previous_symbol2 * alphabet_size);
previous_symbol2 = previous_symbol;
if (order_2[temp] != 0)
{
if (order_2[temp]->get_range(symbol,low_count,high_count,total_count))
{
// there was an entry for this symbol in this context
// update the count for this symbol
order_2[temp]->increment_count(symbol,2);
// encode this symbol
coder.encode(low_count,high_count,total_count);
previous_symbol = symbol;
return;
}
// there was no entry for this symbol in this context so we must
// escape to order-1
// escape to the order-1 context
order_2[temp]->get_range(alphabet_size,low_count,high_count,total_count);
coder.encode(low_count,high_count,total_count);
// increment the count for the escape symbol
order_2[temp]->increment_count(alphabet_size);
}
else
{
order_2[temp] = new cc_high(gs_high);
// in this case the decoder knows to escape to order-1 because
// there was no conditioning_class object in this context yet.
// so we don't need to actually write the escape symbol
}
// update the count for this symbol in this context
order_2[temp]->increment_count(symbol,2);
}
// order-1 context stuff
{
cc& context = *order_1[previous_symbol];
// if we have seen this symbol in the order-1 context
if (context.get_range(symbol,low_count,high_count,total_count))
{
// update the count for this symbol
context.increment_count(symbol,2);
// encode this symbol
coder.encode(low_count,high_count,total_count);
previous_symbol = symbol;
return;
}
// we didn't find the symbol in the order-1 context so we must escape to a
// lower context.
// escape to the order-0 context
context.get_range(alphabet_size,low_count,high_count,total_count);
coder.encode(low_count,high_count,total_count);
// increment counts for the escape symbol and the current symbol
context.increment_count(alphabet_size);
context.increment_count(symbol,2);
}
previous_symbol = symbol;
// if we have seen this symbol in the order-0 context
if (order_0.get_range(symbol,low_count,high_count,total_count))
{
// update the count for this symbol
order_0.increment_count(symbol,2);
// encode this symbol
coder.encode(low_count,high_count,total_count);
return;
}
// if we are here then the symbol does not appear in the order-0 context
// since we have never seen the current symbol in this context
// escape from order-0 context
order_0.get_range(alphabet_size,low_count,high_count,total_count);
coder.encode(low_count,high_count,total_count);
// increment the count for the escape symbol
order_0.increment_count(alphabet_size);
// update the count for this symbol
order_0.increment_count(symbol,2);
// use order minus one context
coder.encode(symbol,symbol+1,alphabet_size);
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_3_