Transformation de Burrows-Wheeler


22 juillet 2007

J'avais besoin d'un programme qui réalisait la transformation de Burrows-Wheeler (TBW) sur de simples lignes de texte et non pas sur des énormes fichiers binaires comme c'est le cas d'habitude. J'ai donc pondu le code qui suit :

#include <iostream>

int LineLen;

int Cmp(const void* a,const void*b)
{
    return strncmp(*(const char**)a,*(const char**)b,LineLen);
}

int main()
{
    int i;
    char    *Line=new char[1000], **Rows=new char*[1000];
    while(gets(Line)){
        LineLen = strlen(Line);
        //On utilise un double buffer pour la ligne courante
        memcpy(Line+LineLen, Line, LineLen);
        //Les permutations en utilisant de simples pointeurs
        for(i=0; i<LineLen; i++)        Rows[i]=Line+i;
        //On trie les pointeurs en fonction de leurs données
        qsort(Rows, LineLen, 4, Cmp);
        //On cherche la ligne originale dans la liste triée.
        i=0;
        while (i<LineLen && strncmp(Rows[i], Line, LineLen))    i++;
        int OriginalIndex = i;
        //
        printf("%d\t",OriginalIndex);
        for(i=0; i<LineLen; i++)    printf("%c", Rows[i][LineLen-1]);
        printf("\n");
    }
    delete []Line;
    delete []Rows;
}

pour les données d'entrée suivante :

ABCABC
abracadabra
BurrowsWheelerTransform
gaattcctgggcctggggctgtggcagctgcctcgtccct
tcacctcctggcttattctctccctccatatcttagcaat
ctcatgcctgtaatcccagcattttggtaggccaaggcgg
gtcggatcacctgaggtcaggagttcgagggccagcctga
tgaccatggtgaaaccccatctctactaaaaatacaaaat
taatcgggcatggtggcacatgcctgtaatcccagctact
ctgaggcaggagaatcgcttaaacccaggaagtggaggtt
tcagtgagctgagattgtgccattgcactccagcctgggt
aacaagagcaaaactccatcaaaaaaaataatatatgtat
atatatattacaattttatatatatatacacattatgtaa
taccattttatatatatacattacgtaatggtaaatgttt
gatcgtctccctggagaataatccccaatgtgaaattact
ctaagtggtgggattacaggcgtgtgcccaacttttcctg
agccttttgaggctgacaccagaggtagaagcccagcctc
tccccactggccatgtggggagaggctccagcctgcagca
accagggatctggcctcaagtgatgccccaacagtgggcg
1001110010001111110101011101101110010100
1100111011000100110110010000011011100111
1000100001000001010101101000010110000011
0000000000111111000100100001011010100011
0011011000001111001010010001001011101111
0010110110101011100100010011000000010000
1101011110010100001000111001000100011001
0011001010001001001110100000101001001101
1110110100001001100110001010101001100100
1110001011101110110000110100011011100001

le programme renvoie :

0   CCAABB
2   rdarcaaaabb
0   mrsrhelsWerafreToruwnBo
16  gcagtgctgtccgccgtgtgagtggtgtctgtcccgccca
28  cctctatgtcttcatctctctgagttattcccctacccaa
17  ctctaacccctggctgggcagtggaacttgggcaatctta
31  cccgggggtctgagttcccttgggaacgaagaaagtgccg
37  tacgaaaaatgataccaacccacaatttttgcaccagtaa
31  ttctcaaccgcagctgtgcaggtatgcttggtcaaagacc
17  taggagccggaacgcattggagtggcaataaagtatcgcg
29  cgcgccggctctggagcttattaatgatgtccgtgctgaa
8   caaacaaatacataaagtaatcttgactaaataagaaaca
11  tacttctttttattttcaaaatgtaaaaataataaatata
25  ttatttttttaaccacaatgctggattaaataatatttga
25  ggtcatgaagaacccttcttactagttctatacaggccaa
13  cttacagcacgtggcagtgtgatttgaccttgcgggattc
7   ggctcaccggacctacgggcgcattaaaagaaggcctttc
35  cgccgcccgcgcctgctggcagatagaggtagttcaccga
3   ccagcacggctcacacgggctcgttgggtgataacagacg
21  1111100100111011001010010110111100010110
30  1010101011001100100011011111001110010010
30  1110100100000000001010111001001100000100
0   1000001010101000001010010101000100101110
8   1010101110010001010110010101010110111000
13  1010000010010010001010111100101010001000
35  1101110010011000010001000011101011010100
9   1010011101111110100000000000100010010100
39  1010101111110011000010011100010001000010
36  1110100000101001110111011110011010101000

Je voulais un code qui soit rapide à implémenter mais :

  • la limite de 1000 octets n'est pas terrible pour une routine généraliste.
  • j'utilise qsort qui n'est pas optimal par rapport à mon radix sort pour des données de taille importante.
  • J'utilise gets ce qui est déconseillé !
  • On n'a pas à dupliquer la ligne de données, en compliquant un peu le code ça devrait pouvoir marcher.
  • Le buffer Rows est de trop il faut trouver une astuce pour ne pas l'utiliser il prend une mémoire folle.

Tout ceci sera fixé plus loin, pour l'instant ce qui nous intéresse c'est d'avoir un outil de test à utiliser en conjonction avec d'autres compresseurs maison.

La transformation inverse

Maintenant que l'exécutable précédent (que j'ai appelé bwt) est fait et fonctionne, comment retrouver à partir de sa sortie les données originales ?

Accueil