/*
Copyright (c) 2004 Amir Said (said@ieee.org) & William A. Pearlman (pearlw@ecse.rpi.edu)
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

-   Redistributions of source code must retain the above copyright notice, this list 
    of conditions and the following disclaimer. 

-   Redistributions in binary form must reproduce the above copyright notice, this list of 
    conditions and the following disclaimer in the documentation and/or other materials 
    provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.

*/
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//                                                                           -
//                       ****************************                        -
//                        ARITHMETIC CODING EXAMPLES                         -
//                       ****************************                        -
//                                                                           -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//                                                                           -
// Fast arithmetic coding implementation                                     -
// -> 32-bit variables, 32-bit product, periodic updates, table decoding     -
//                                                                           -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//                                                                           -
// Version 1.00  -  April 25, 2004                                           -
//                                                                           -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//                                                                           -
//                                  WARNING                                  -
//                                 =========                                 -
//                                                                           -
// The only purpose of this program is to demonstrate the basic principles   -
// of arithmetic coding. It is provided as is, without any express or        -
// implied warranty, without even the warranty of fitness for any particular -
// purpose, or that the implementations are correct.                         -
//                                                                           -
// Permission to copy and redistribute this code is hereby granted, provided -
// that this warning and copyright notices are not removed or altered.       -
//                                                                           -
// Copyright (c) 2004 by Amir Said (said@ieee.org) &                         -
//                       William A. Pearlman (pearlw@ecse.rpi.edu)           -
//                                                                           -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//                                                                           -
// A description of the arithmetic coding method used here is available in   -
//                                                                           -
// Lossless Compression Handbook, ed. K. Sayood                              -
// Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 -
//                                                                           -
// A. Said, Introduction to Arithetic Coding Theory and Practice             -
// HP Labs report HPL-2004-76  -  http://www.hpl.hp.com/techreports/         -
//                                                                           -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


// - - Inclusion - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

#include <stdlib.h>
#include "o3dgcArithmeticCodec.h"

namespace o3dgc
{
    // - - Constants - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    const unsigned AC__MinLength = 0x01000000U;   // threshold for renormalization
    const unsigned AC__MaxLength = 0xFFFFFFFFU;      // maximum AC interval length

                                               // Maximum values for binary models
    const unsigned BM__LengthShift = 13;     // length bits discarded before mult.
    const unsigned BM__MaxCount    = 1 << BM__LengthShift;  // for adaptive models

                                              // Maximum values for general models
    const unsigned DM__LengthShift = 15;     // length bits discarded before mult.
    const unsigned DM__MaxCount    = 1 << DM__LengthShift;  // for adaptive models


    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // - - Static functions  - - - - - - - - - - - - - - - - - - - - - - - - - - -

    static void AC_Error(const char * msg)
    {
      fprintf(stderr, "\n\n -> Arithmetic coding error: ");
      fputs(msg, stderr);
      fputs("\n Execution terminated!\n", stderr);
      getchar();
      exit(1);
    }


    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // - - Coding implementations  - - - - - - - - - - - - - - - - - - - - - - - -

    inline void Arithmetic_Codec::propagate_carry(void)
    {
      unsigned char * p;            // carry propagation on compressed data buffer
      for (p = ac_pointer - 1; *p == 0xFFU; p--) *p = 0;
      ++*p;
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    inline void Arithmetic_Codec::renorm_enc_interval(void)
    {
      do {                                          // output and discard top byte
        *ac_pointer++ = (unsigned char)(base >> 24);
        base <<= 8;
      } while ((length <<= 8) < AC__MinLength);        // length multiplied by 256
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    inline void Arithmetic_Codec::renorm_dec_interval(void)
    {
      do {                                          // read least-significant byte
        value = (value << 8) | unsigned(*++ac_pointer);
      } while ((length <<= 8) < AC__MinLength);        // length multiplied by 256
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Arithmetic_Codec::put_bit(unsigned bit)
    {
    #ifdef _DEBUG
      if (mode != 1) AC_Error("encoder not initialized");
    #endif

      length >>= 1;                                              // halve interval
      if (bit) {
        unsigned init_base = base;
        base += length;                                               // move base
        if (init_base > base) propagate_carry();               // overflow = carry
      }

      if (length < AC__MinLength) renorm_enc_interval();        // renormalization
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    unsigned Arithmetic_Codec::get_bit(void)
    {
    #ifdef _DEBUG
      if (mode != 2) AC_Error("decoder not initialized");
    #endif

      length >>= 1;                                              // halve interval
      unsigned bit = (value >= length);                              // decode bit
      if (bit) value -= length;                                       // move base

      if (length < AC__MinLength) renorm_dec_interval();        // renormalization

      return bit;                                         // return data bit value
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Arithmetic_Codec::put_bits(unsigned data, unsigned bits)
    {
    #ifdef _DEBUG
      if (mode != 1) AC_Error("encoder not initialized");
      if ((bits < 1) || (bits > 20)) AC_Error("invalid number of bits");
      if (data >= (1U << bits)) AC_Error("invalid data");
    #endif

      unsigned init_base = base;
      base += data * (length >>= bits);            // new interval base and length

      if (init_base > base) propagate_carry();                 // overflow = carry
      if (length < AC__MinLength) renorm_enc_interval();        // renormalization
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    unsigned Arithmetic_Codec::get_bits(unsigned bits)
    {
    #ifdef _DEBUG
      if (mode != 2) AC_Error("decoder not initialized");
      if ((bits < 1) || (bits > 20)) AC_Error("invalid number of bits");
    #endif

      unsigned s = value / (length >>= bits);      // decode symbol, change length

      value -= length * s;                                      // update interval
      if (length < AC__MinLength) renorm_dec_interval();        // renormalization

      return s;
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Arithmetic_Codec::encode(unsigned bit,
                                  Static_Bit_Model & M)
    {
    #ifdef _DEBUG
      if (mode != 1) AC_Error("encoder not initialized");
    #endif

      unsigned x = M.bit_0_prob * (length >> BM__LengthShift);   // product l x p0
                                                                // update interval
      if (bit == 0)
        length  = x;
      else {
        unsigned init_base = base;
        base   += x;
        length -= x;
        if (init_base > base) propagate_carry();               // overflow = carry
      }

      if (length < AC__MinLength) renorm_enc_interval();        // renormalization
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    unsigned Arithmetic_Codec::decode(Static_Bit_Model & M)
    {
    #ifdef _DEBUG
      if (mode != 2) AC_Error("decoder not initialized");
    #endif

      unsigned x = M.bit_0_prob * (length >> BM__LengthShift);   // product l x p0
      unsigned bit = (value >= x);                                     // decision
                                                        // update & shift interval
      if (bit == 0)
        length  = x;
      else {
        value  -= x;                                 // shifted interval base = 0
        length -= x;
      }

      if (length < AC__MinLength) renorm_dec_interval();        // renormalization

      return bit;                                         // return data bit value
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Arithmetic_Codec::encode(unsigned bit,
                                  Adaptive_Bit_Model & M)
    {
    #ifdef _DEBUG
      if (mode != 1) AC_Error("encoder not initialized");
    #endif

      unsigned x = M.bit_0_prob * (length >> BM__LengthShift);   // product l x p0
                                                                // update interval
      if (bit == 0) {
        length = x;
        ++M.bit_0_count;
      }
      else {
        unsigned init_base = base;
        base   += x;
        length -= x;
        if (init_base > base) propagate_carry();               // overflow = carry
      }

      if (length < AC__MinLength) renorm_enc_interval();        // renormalization

      if (--M.bits_until_update == 0) M.update();         // periodic model update
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    unsigned Arithmetic_Codec::decode(Adaptive_Bit_Model & M)
    {
    #ifdef _DEBUG
      if (mode != 2) AC_Error("decoder not initialized");
    #endif

      unsigned x = M.bit_0_prob * (length >> BM__LengthShift);   // product l x p0
      unsigned bit = (value >= x);                                     // decision
                                                                // update interval
      if (bit == 0) {
        length = x;
        ++M.bit_0_count;
      }
      else {
        value  -= x;
        length -= x;
      }

      if (length < AC__MinLength) renorm_dec_interval();        // renormalization

      if (--M.bits_until_update == 0) M.update();         // periodic model update

      return bit;                                         // return data bit value
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Arithmetic_Codec::encode(unsigned data,
                                  Static_Data_Model & M)
    {
    #ifdef _DEBUG
      if (mode != 1) AC_Error("encoder not initialized");
      if (data >= M.data_symbols) AC_Error("invalid data symbol");
    #endif

      unsigned x, init_base = base;
                                                               // compute products
      if (data == M.last_symbol) {
        x = M.distribution[data] * (length >> DM__LengthShift);
        base   += x;                                            // update interval
        length -= x;                                          // no product needed
      }
      else {
        x = M.distribution[data] * (length >>= DM__LengthShift);
        base   += x;                                            // update interval
        length  = M.distribution[data+1] * length - x;
      }
             
      if (init_base > base) propagate_carry();                 // overflow = carry

      if (length < AC__MinLength) renorm_enc_interval();        // renormalization
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    unsigned Arithmetic_Codec::decode(Static_Data_Model & M)
    {
    #ifdef _DEBUG
      if (mode != 2) AC_Error("decoder not initialized");
    #endif

      unsigned n, s, x, y = length;

      if (M.decoder_table) {              // use table look-up for faster decoding

        unsigned dv = value / (length >>= DM__LengthShift);
        unsigned t = dv >> M.table_shift;

        s = M.decoder_table[t];         // initial decision based on table look-up
        n = M.decoder_table[t+1] + 1;

        while (n > s + 1) {                        // finish with bisection search
          unsigned m = (s + n) >> 1;
          if (M.distribution[m] > dv) n = m; else s = m;
        }
                                                               // compute products
        x = M.distribution[s] * length;
        if (s != M.last_symbol) y = M.distribution[s+1] * length;
      }

      else {                                  // decode using only multiplications

        x = s = 0;
        length >>= DM__LengthShift;
        unsigned m = (n = M.data_symbols) >> 1;
                                                    // decode via bisection search
        do {
          unsigned z = length * M.distribution[m];
          if (z > value) {
            n = m;
            y = z;                                             // value is smaller
          }
          else {
            s = m;
            x = z;                                     // value is larger or equal
          }
        } while ((m = (s + n) >> 1) != s);
      }

      value -= x;                                               // update interval
      length = y - x;

      if (length < AC__MinLength) renorm_dec_interval();        // renormalization

      return s;
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Arithmetic_Codec::encode(unsigned data,
                                  Adaptive_Data_Model & M)
    {
    #ifdef _DEBUG
      if (mode != 1) AC_Error("encoder not initialized");
      if (data >= M.data_symbols) 
      {
          AC_Error("invalid data symbol");
      }
    #endif

      unsigned x, init_base = base;
                                                               // compute products
      if (data == M.last_symbol) {
        x = M.distribution[data] * (length >> DM__LengthShift);
        base   += x;                                            // update interval
        length -= x;                                          // no product needed
      }
      else {
        x = M.distribution[data] * (length >>= DM__LengthShift);
        base   += x;                                            // update interval
        length  = M.distribution[data+1] * length - x;
      }

      if (init_base > base) propagate_carry();                 // overflow = carry

      if (length < AC__MinLength) renorm_enc_interval();        // renormalization

      ++M.symbol_count[data];
      if (--M.symbols_until_update == 0) M.update(true);  // periodic model update
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    unsigned Arithmetic_Codec::decode(Adaptive_Data_Model & M)
    {
    #ifdef _DEBUG
      if (mode != 2) AC_Error("decoder not initialized");
    #endif

      unsigned n, s, x, y = length;

      if (M.decoder_table) {              // use table look-up for faster decoding

        unsigned dv = value / (length >>= DM__LengthShift);
        unsigned t = dv >> M.table_shift;

        s = M.decoder_table[t];         // initial decision based on table look-up
        n = M.decoder_table[t+1] + 1;

        while (n > s + 1) {                        // finish with bisection search
          unsigned m = (s + n) >> 1;
          if (M.distribution[m] > dv) n = m; else s = m;
        }
                                                               // compute products
        x = M.distribution[s] * length;
        if (s != M.last_symbol) {
            y = M.distribution[s+1] * length;
        }
      }

      else {                                  // decode using only multiplications

        x = s = 0;
        length >>= DM__LengthShift;
        unsigned m = (n = M.data_symbols) >> 1;
                                                    // decode via bisection search
        do {
          unsigned z = length * M.distribution[m];
          if (z > value) {
            n = m;
            y = z;                                             // value is smaller
          }
          else {
            s = m;
            x = z;                                     // value is larger or equal
          }
        } while ((m = (s + n) >> 1) != s);
      }

      value -= x;                                               // update interval
      length = y - x;

      if (length < AC__MinLength) renorm_dec_interval();        // renormalization

      ++M.symbol_count[s];
      if (--M.symbols_until_update == 0) M.update(false);  // periodic model update

      return s;
    }


    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // - - Other Arithmetic_Codec implementations  - - - - - - - - - - - - - - - -

    Arithmetic_Codec::Arithmetic_Codec(void)
    {
      mode = buffer_size = 0;
      new_buffer = code_buffer = 0;
    }

    Arithmetic_Codec::Arithmetic_Codec(unsigned max_code_bytes,
                                       unsigned char * user_buffer)
    {
      mode = buffer_size = 0;
      new_buffer = code_buffer = 0;
      set_buffer(max_code_bytes, user_buffer);
    }

    Arithmetic_Codec::~Arithmetic_Codec(void)
    {
      delete [] new_buffer;
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Arithmetic_Codec::set_buffer(unsigned max_code_bytes,
                                      unsigned char * user_buffer)
    {
                                                      // test for reasonable sizes
      if (!max_code_bytes)// || (max_code_bytes > 0x10000000U)) // updated by K. Mammou
      {
        AC_Error("invalid codec buffer size");
      }
      if (mode != 0) AC_Error("cannot set buffer while encoding or decoding");

      if (user_buffer != 0) {                       // user provides memory buffer
        buffer_size = max_code_bytes;
        code_buffer = user_buffer;               // set buffer for compressed data
        delete [] new_buffer;                 // free anything previously assigned
        new_buffer = 0;
        return;
      }

      if (max_code_bytes <= buffer_size) return;               // enough available

      buffer_size = max_code_bytes;                           // assign new memory
      delete [] new_buffer;                   // free anything previously assigned
      if ((new_buffer = new unsigned char[buffer_size+16]) == 0) // 16 extra bytes
        AC_Error("cannot assign memory for compressed data buffer");
      code_buffer = new_buffer;                  // set buffer for compressed data
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Arithmetic_Codec::start_encoder(void)
    {
      if (mode != 0) AC_Error("cannot start encoder");
      if (buffer_size == 0) AC_Error("no code buffer set");

      mode   = 1;
      base   = 0;            // initialize encoder variables: interval and pointer
      length = AC__MaxLength;
      ac_pointer = code_buffer;                       // pointer to next data byte
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Arithmetic_Codec::start_decoder(void)
    {
      if (mode != 0) AC_Error("cannot start decoder");
      if (buffer_size == 0) AC_Error("no code buffer set");

                      // initialize decoder: interval, pointer, initial code value
      mode   = 2;
      length = AC__MaxLength;
      ac_pointer = code_buffer + 3;
      value = (unsigned(code_buffer[0]) << 24)|(unsigned(code_buffer[1]) << 16) |
              (unsigned(code_buffer[2]) <<  8)| unsigned(code_buffer[3]);
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Arithmetic_Codec::read_from_file(FILE * code_file)
    {
      unsigned shift = 0, code_bytes = 0;
      int file_byte;
                          // read variable-length header with number of code bytes
      do {
        if ((file_byte = getc(code_file)) == EOF)
          AC_Error("cannot read code from file");
        code_bytes |= unsigned(file_byte & 0x7F) << shift;
        shift += 7;
      } while (file_byte & 0x80);
                                                           // read compressed data
      if (code_bytes > buffer_size) AC_Error("code buffer overflow");
      if (fread(code_buffer, 1, code_bytes, code_file) != code_bytes)
        AC_Error("cannot read code from file");

      start_decoder();                                       // initialize decoder
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    unsigned Arithmetic_Codec::stop_encoder(void)
    {
      if (mode != 1) AC_Error("invalid to stop encoder");
      mode = 0;

      unsigned init_base = base;            // done encoding: set final data bytes

      if (length > 2 * AC__MinLength) {
        base  += AC__MinLength;                                     // base offset
        length = AC__MinLength >> 1;             // set new length for 1 more byte
      }
      else {
        base  += AC__MinLength >> 1;                                // base offset
        length = AC__MinLength >> 9;            // set new length for 2 more bytes
      }

      if (init_base > base) propagate_carry();                 // overflow = carry

      renorm_enc_interval();                // renormalization = output last bytes

      unsigned code_bytes = unsigned(ac_pointer - code_buffer);
      if (code_bytes > buffer_size) AC_Error("code buffer overflow");

      return code_bytes;                                   // number of bytes used
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    unsigned Arithmetic_Codec::write_to_file(FILE * code_file)
    {
      unsigned header_bytes = 0, code_bytes = stop_encoder(), nb = code_bytes;

                         // write variable-length header with number of code bytes
      do {
        int file_byte = int(nb & 0x7FU);
        if ((nb >>= 7) > 0) file_byte |= 0x80;
        if (putc(file_byte, code_file) == EOF)
          AC_Error("cannot write compressed data to file");
        header_bytes++;
      } while (nb);
                                                          // write compressed data
      if (fwrite(code_buffer, 1, code_bytes, code_file) != code_bytes)
        AC_Error("cannot write compressed data to file");

      return code_bytes + header_bytes;                              // bytes used
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Arithmetic_Codec::stop_decoder(void)
    {
      if (mode != 2) AC_Error("invalid to stop decoder");
      mode = 0;
    }


    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // - Static bit model implementation - - - - - - - - - - - - - - - - - - - - -

    Static_Bit_Model::Static_Bit_Model(void)
    {
      bit_0_prob = 1U << (BM__LengthShift - 1);                        // p0 = 0.5
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Static_Bit_Model::set_probability_0(double p0)
    {
      if ((p0 < 0.0001)||(p0 > 0.9999)) AC_Error("invalid bit probability");
      bit_0_prob = unsigned(p0 * (1 << BM__LengthShift));
    }


    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // - Adaptive bit model implementation - - - - - - - - - - - - - - - - - - - -

    Adaptive_Bit_Model::Adaptive_Bit_Model(void)
    {
      reset();
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Adaptive_Bit_Model::reset(void)
    {
                                           // initialization to equiprobable model
      bit_0_count = 1;
      bit_count   = 2;
      bit_0_prob  = 1U << (BM__LengthShift - 1);
      update_cycle = bits_until_update = 4;         // start with frequent updates
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Adaptive_Bit_Model::update(void)
    {
                                       // halve counts when a threshold is reached

      if ((bit_count += update_cycle) > BM__MaxCount) {
        bit_count = (bit_count + 1) >> 1;
        bit_0_count = (bit_0_count + 1) >> 1;
        if (bit_0_count == bit_count) ++bit_count;
      }
                                               // compute scaled bit 0 probability
      unsigned scale = 0x80000000U / bit_count;
      bit_0_prob = (bit_0_count * scale) >> (31 - BM__LengthShift);

                                                 // set frequency of model updates
      update_cycle = (5 * update_cycle) >> 2;
      if (update_cycle > 64) update_cycle = 64;
      bits_until_update = update_cycle;
    }


    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // - - Static data model implementation  - - - - - - - - - - - - - - - - - - -

    Static_Data_Model::Static_Data_Model(void)
    {
      data_symbols = 0;
      distribution = 0;
    }

    Static_Data_Model::~Static_Data_Model(void)
    {
      delete [] distribution;
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Static_Data_Model::set_distribution(unsigned number_of_symbols,
                                             const double probability[])
    {
      if ((number_of_symbols < 2) || (number_of_symbols > (1 << 11)))
        AC_Error("invalid number of data symbols");

      if (data_symbols != number_of_symbols) {     // assign memory for data model
        data_symbols = number_of_symbols;
        last_symbol = data_symbols - 1;
        delete [] distribution;
                                         // define size of table for fast decoding
        if (data_symbols > 16) {
          unsigned table_bits = 3;
          while (data_symbols > (1U << (table_bits + 2))) ++table_bits;
          table_size  = 1 << table_bits;
          table_shift = DM__LengthShift - table_bits;
          distribution = new unsigned[data_symbols+table_size+2];
          decoder_table = distribution + data_symbols;
        }
        else {                                  // small alphabet: no table needed
          decoder_table = 0;
          table_size = table_shift = 0;
          distribution = new unsigned[data_symbols];
        }
        if (distribution == 0) AC_Error("cannot assign model memory");
      }
                                 // compute cumulative distribution, decoder table
      unsigned s = 0;
      double sum = 0.0, p = 1.0 / double(data_symbols);

      for (unsigned k = 0; k < data_symbols; k++) {
        if (probability) p = probability[k];
        if ((p < 0.0001) || (p > 0.9999)) AC_Error("invalid symbol probability");
        distribution[k] = unsigned(sum * (1 << DM__LengthShift));
        sum += p;
        if (table_size == 0) continue;
        unsigned w = distribution[k] >> table_shift;
        while (s < w) decoder_table[++s] = k - 1;
      }

      if (table_size != 0) {
        decoder_table[0] = 0;
        while (s <= table_size) decoder_table[++s] = data_symbols - 1;
      }

      if ((sum < 0.9999) || (sum > 1.0001)) AC_Error("invalid probabilities");
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // - - Adaptive data model implementation  - - - - - - - - - - - - - - - - - -

    Adaptive_Data_Model::Adaptive_Data_Model(void)
    {
      data_symbols = 0;
      distribution = 0;
    }

    Adaptive_Data_Model::Adaptive_Data_Model(unsigned number_of_symbols)
    {
      data_symbols = 0;
      distribution = 0;
      set_alphabet(number_of_symbols);
    }

    Adaptive_Data_Model::~Adaptive_Data_Model(void)
    {
      delete [] distribution;
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Adaptive_Data_Model::set_alphabet(unsigned number_of_symbols)
    {
      if ((number_of_symbols < 2) || (number_of_symbols > (1 << 11)))
        AC_Error("invalid number of data symbols");

      if (data_symbols != number_of_symbols) {     // assign memory for data model
        data_symbols = number_of_symbols;
        last_symbol = data_symbols - 1;
        delete [] distribution;
                                         // define size of table for fast decoding
        if (data_symbols > 16) {
          unsigned table_bits = 3;
          while (data_symbols > (1U << (table_bits + 2))) ++table_bits;
          table_size  = 1 << table_bits;
          table_shift = DM__LengthShift - table_bits;
          distribution = new unsigned[2*data_symbols+table_size+2];
          decoder_table = distribution + 2 * data_symbols;
        }
        else {                                  // small alphabet: no table needed
          decoder_table = 0;
          table_size = table_shift = 0;
          distribution = new unsigned[2*data_symbols];
        }
        symbol_count = distribution + data_symbols;
        if (distribution == 0) AC_Error("cannot assign model memory");
      }

      reset();                                                 // initialize model
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Adaptive_Data_Model::update(bool from_encoder)
    {
                                       // halve counts when a threshold is reached

      if ((total_count += update_cycle) > DM__MaxCount) {
        total_count = 0;
        for (unsigned n = 0; n < data_symbols; n++)
          total_count += (symbol_count[n] = (symbol_count[n] + 1) >> 1);
      }
                                 // compute cumulative distribution, decoder table
      unsigned k, sum = 0, s = 0;
      unsigned scale = 0x80000000U / total_count;

      if (from_encoder || (table_size == 0))
        for (k = 0; k < data_symbols; k++) {
          distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
          sum += symbol_count[k];
        }
      else {
        for (k = 0; k < data_symbols; k++) {
          distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
          sum += symbol_count[k];
          unsigned w = distribution[k] >> table_shift;
          while (s < w) decoder_table[++s] = k - 1;
        }
        decoder_table[0] = 0;
        while (s <= table_size) decoder_table[++s] = data_symbols - 1;
      }
                                                 // set frequency of model updates
      update_cycle = (5 * update_cycle) >> 2;
      unsigned max_cycle = (data_symbols + 6) << 3;
      if (update_cycle > max_cycle) update_cycle = max_cycle;
      symbols_until_update = update_cycle;
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    void Adaptive_Data_Model::reset(void)
    {
      if (data_symbols == 0) return;

                          // restore probability estimates to uniform distribution
      total_count = 0;
      update_cycle = data_symbols;
      for (unsigned k = 0; k < data_symbols; k++) symbol_count[k] = 1;
      update(false);
      symbols_until_update = update_cycle = (data_symbols + 6) >> 1;
    }
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
