Aritmetic coding (python)

De GirinoWiki

#!/usr/bin/python
# coding: iso-8859-15
 
import sys
 
#SIZE_DEF = 16
#BASE_DEF = 2
 
# este parâmetros definemo número de dígitos a serem usados e
# a base desses dígitos. BASE_DEF = 10 indica base decimal.
# BASE_DEF = 2 indica base binária. BASE_DEF = 16, hexadecimal.
# Qualquer valor de base pode ser usado aqui.
SIZE_DEF = 5
BASE_DEF = 10
 
LOW_DEF =  0
HIGH_DEF = BASE_DEF**SIZE_DEF-1
MOD_DEF =  BASE_DEF**(SIZE_DEF-1)
 
 
def count_freq(str):
    """
        Esta função conta a frequência de ocorrência dos
        caracteres no arquivo de entrada.
    """
    size = len(str)
    count = dict()
    for i in range(0, size):
        char = str[i]
        if count.has_key(char):
            count[char] = count[char] + 1
        else:
            count[char] = 1
    return count
 
def build_intervals(count):
    """
        Esta função constrói a tabela de freqüências acumuladas 
        necessária à codificação aritmética.
    """
    begin = 0
    end = 0
    intervals = dict()
    for key in count.keys():
        begin = end
        end = end + count[key]
        intervals[key] = [begin, end]
    return intervals
 
def encode(str):
    """
        Esta função codifica usando codificação aritmética
        uma cadeia de caracteres "str". A implementação usa a 
        técnica descrita em 
        http://pt.wikipedia.org/wiki/Codifica%C3%A7%C3%A3o_aritm%C3%A9tica#C.C3.A1lculo_com_precis.C3.A3o_finita
        para representar a codificação usando precisão finita. Entretanto
        não é utilizada a tecnica descrita para se evitar underflow. Neste
        caso o programa irá falhar entrando em "loop" infinito.
    """
    # calculam-se os intervalos
    intervals = build_intervals(count_freq(str))
    size = len(str)
    low = LOW_DEF
    high = HIGH_DEF
    ret = [] # inicializa o vetor de retorno
    # itera-se sobre todo o arquivo de entrata (str)
    for i in range(0, len(str)):
        char = str[i]
        interval = intervals[char]
        begin = interval[0]
        end = interval[1]
        # recalcula-se o tamanho do intervalo atual
        oldlow = low
        low = oldlow + (high-oldlow+1) * begin/size
        high = oldlow + (high-oldlow+1) * end/size -1
        # caso os primeiros dígitos sejam iguais, podemos
        # eliminá-los da rpresentação finita e emitílos na saída
        while (high / MOD_DEF) == (low / MOD_DEF):
            ret = ret + [high / MOD_DEF]
            high = (high - (MOD_DEF * (high / MOD_DEF))) * BASE_DEF + (BASE_DEF-1)
            low = (low - (MOD_DEF * (low / MOD_DEF))) * BASE_DEF
    # como não nos interessa a "melhor" codificação possível, 
    # podemos usar o limite inferior do intervalo como codificação com
    # muito pouco prejuíso.
    while low > 0:
        ret = ret + [low / MOD_DEF]
        low = (low - (MOD_DEF * (low / MOD_DEF))) * BASE_DEF
    return [ret, intervals, len(str)]
 
def decode(val, intervals, size):
    """
        Esta função é análoga a função "encode", e realiza o processo
        inverso. As mesmas premissas devemser consideradas neste caso.
    """
    # inicializa o arquivo (string) de retorno
    ret = ""
    low = LOW_DEF
    high = HIGH_DEF
    code = 0
    # lemos os primeiros dígitos do código
    for x in val[0:SIZE_DEF]:
        code = code * BASE_DEF + x
    pos = SIZE_DEF
    # e produzimos todos os caracteres da entrada, na saída
    for i in range(0, size):
        # o "index" é a posição na tabela de probabilidades
        # que representa o intervalo atual 
        index = int(((code-low+1)*size-1)/(high-low+1))
        # temos de iterar por toda a tabela par aencontrar o intervalo
        for key in intervals.keys():
            interval = intervals[key]
            begin = interval[0]
            end = interval[1]
            if index >= begin and index < end:
                ret = ret + key
                oldlow = low
                low = oldlow + (high-oldlow+1) * begin/size
                high = oldlow + (high-oldlow+1) * end/size -1
                break
        # e podemos eliminar os primeiros dígitos quando eles forem
        # repetidos, lendo o próximo dígito do código
        while (high / MOD_DEF) == (low / MOD_DEF):
            code = (code - (MOD_DEF * (code / MOD_DEF))) * BASE_DEF
            if pos < len(val):
                code = code + val[pos]
                pos = pos + 1
            high = (high - (MOD_DEF * (high / MOD_DEF))) * BASE_DEF + (BASE_DEF-1)
            low = (low - (MOD_DEF * (low / MOD_DEF))) * BASE_DEF
    return ret
 
str = 'A_ASA_DA_CASA'
encoded = encode(str)
print encoded
decoded = decode(encoded[0], encoded[1], encoded[2])
print decoded
Ferramentas pessoais
Social Blogging
  • StumbleUpon
  • Adicionar aos Favoritos BlogBlogs
  • Adicionar esta página no Linkk
  • Add to Technorati Favorites
patrocinadores
Espaço comercial