Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

ppm.cpp

Go to the documentation of this file.
00001 #include <stdlib.h>
00002 #include <stdio.h>
00003 #include "arith.h"
00004 #include "ppm.h"
00005 
00006 /****************************************************************************
00007  * Gestion des noeuds
00008  ****************************************************************************/
00009 
00010 /* 
00011  * Désallocation du noeud p
00012  */
00013 
00014 void ppm_worker::Node_Free(UINT p) {
00015   node_heap[node_free_last].free_next=p;
00016   node_heap[p].free_next=NIL;
00017   node_free_last=p;
00018   node_free_nb++;
00019 }
00020 
00021 /*
00022  * Allocation d'un noeud
00023  * s'il ne reste plus de place, on désalloue le contexte le moins utilisé.
00024  */
00025 
00026 UINT ppm_worker::Node_Alloc(void)  {
00027   UINT p;
00028   if (node_free_nb<=2) Context_DeleteLast();
00029   p=node_free_first;
00030   node_free_first=node_heap[node_free_first].free_next;
00031   node_free_nb--;
00032 #ifdef DEBUG
00033   printf("Node_Alloc: p=%d\n",p);
00034 #endif
00035   return p;
00036 }
00037 
00038 /****************************************************************************
00039  * Gestion des contextes 
00040  ****************************************************************************/
00041 
00042 
00043 /* 
00044  * Mise au début de la liste des contextes du contexte c 
00045  */
00046 void ppm_worker::Context_MoveFirst(UINT c) {
00047   NODE *ctx;
00048    
00049   if (c!=ctx_first)  {
00050     ctx=&node_heap[c];
00051     /* suppression du contexte dans la liste */
00052     if (c==ctx_last)  {
00053       ctx_last=ctx->hdr.ctx_prev;
00054     } else  {
00055       node_heap[ctx->hdr.ctx_prev].hdr.ctx_next=ctx->hdr.ctx_next;
00056       node_heap[ctx->hdr.ctx_next].hdr.ctx_prev=ctx->hdr.ctx_prev;
00057     }
00058     /* insertion au début de la liste */
00059     node_heap[ctx_first].hdr.ctx_prev=c;
00060     ctx->hdr.ctx_next=ctx_first;
00061     ctx_first=c;
00062   }
00063 }
00064 
00065 /*
00066  * Destruction du contexte le moins utilisé (ctx_last)
00067  */
00068 void ppm_worker::Context_DeleteLast(void) {
00069   NODE *n;
00070   UINT h,h_next,node,node_next;
00071   USHORT *p;
00072    
00073   n=&node_heap[ctx_last];
00074    
00075   /* libération dans la table de hachage. Comme on ne dispose pas de
00076    * pointeur hash_prev dans les contextes, il faut parcourir toute
00077    * la liste. Heureusement, celle-ci est de longueur faible en moyenne
00078    */
00079   h_next=n->hdr.hash_next;
00080   h=h_next;
00081   while (h<HASH_ADDRESS) h=node_heap[h].hdr.hash_next;
00082   p=&hash_table[h-HASH_ADDRESS];
00083   while (*p!=ctx_last) p=&node_heap[*p].hdr.hash_next;
00084   *p=h_next;
00085    
00086   /* libération des noeuds & modification de ctx_last */
00087    
00088   if (n->hdr.sf_max>=2)  {
00089     node=n->hdr.sf.l.sf_next;
00090     while (1) {
00091       node_next=node_heap[node].sf.sf_next;
00092       Node_Free(node);
00093       if (node_next==NIL) break;
00094       node=node_next;
00095     }
00096   } 
00097 
00098   node=ctx_last;
00099   ctx_last=n->hdr.ctx_prev;
00100   Node_Free(node);
00101   ctx_nb--;
00102 }
00103 
00104 /* 
00105  * Création d'un nouveau contexte avec un seul symbole sym de fréquence 1
00106  * Utilisation implicite de sym_context et sym_hash.
00107  * Libération de mémoire si nécessaire, et mise en premier dans la liste
00108  */
00109 void ppm_worker::Context_New(int sym,int order) {
00110   NODE *ctx;
00111   UINT i,c;
00112 
00113 #ifdef DEBUG   
00114   printf("Context_New: sym=%d o=%d\n",sym,order);
00115 #endif
00116 
00117   c=Node_Alloc();
00118   ctx=&node_heap[c];
00119    
00120   /* mise du contexte en tête de la liste */
00121   ctx->hdr.ctx_next=ctx_first;
00122   node_heap[ctx_first].hdr.ctx_prev=c;
00123   ctx_first=c;
00124   ctx_nb++;
00125    
00126   /* insertion dans la table de hachage */
00127   ctx->hdr.hash_next=hash_table[sym_hash[order]];
00128   hash_table[sym_hash[order]]=ctx_first;
00129 
00130   /* initialisation du contexte */
00131   ctx->hdr.order=order;
00132   for(i=0;i<order;i++) ctx->hdr.sym[i]=sym_context[i+1];
00133 
00134   ctx->hdr.sf_max=0;
00135   ctx->hdr.sf.sf[0].sym=sym;
00136   ctx->hdr.sf.sf[0].freq=1;
00137 #ifdef DEBUG
00138   Context_Print(ctx_first);
00139 #endif
00140 }
00141 
00142 /*
00143  * Ajout d'un nouveau symbole au contexte c
00144  */
00145 
00146 void ppm_worker::Context_NewSym(int sym,UINT c) {
00147   NODE *n,*m;
00148   UINT p,sf_max;
00149 
00150 #ifdef DEBUG   
00151   printf("Context_NewSym: sym=%d c=%d\n",sym,c);
00152   Context_Print(c);
00153 #endif
00154 
00155   n=&node_heap[c];
00156   sf_max=n->hdr.sf_max;
00157   n->hdr.sf_max++;
00158   if (sf_max==0)  {
00159     n->hdr.sf.sf[1].sym=sym;
00160     n->hdr.sf.sf[1].freq=1;
00161   } else if (sf_max==1)  {
00162     p=Node_Alloc();
00163     m=&node_heap[p];
00164     m->sf.sf[0]=n->hdr.sf.sf[0];
00165     m->sf.sf[1]=n->hdr.sf.sf[1];
00166     m->sf.sf[2].sym=sym;
00167     m->sf.sf[2].freq=1;
00168     m->sf.sf_next=NIL;
00169     n->hdr.sf.l.sf_next=p;
00170     n->hdr.sf.l.freq_tot=((UINT)m->sf.sf[0].freq+(UINT)m->sf.sf[1].freq+1);
00171   } else  {
00172     n->hdr.sf.l.freq_tot++;
00173     m=&node_heap[n->hdr.sf.l.sf_next];
00174     while (sf_max>=NODE_SFNB)  {
00175       sf_max-=NODE_SFNB;
00176       m=&node_heap[m->sf.sf_next];
00177     }
00178     sf_max++;
00179     if (sf_max==NODE_SFNB)  {
00180       p=Node_Alloc();
00181       m->sf.sf_next=p;
00182       m=&node_heap[p];
00183       m->sf.sf_next=NIL;
00184       sf_max=0;
00185     }
00186     m->sf.sf[sf_max].sym=sym;
00187     m->sf.sf[sf_max].freq=1;
00188   }
00189 #ifdef DEBUG
00190   Context_Print(c);
00191 #endif
00192 }
00193 
00194 
00195 #ifdef STAT
00196 int hash_nb=1;
00197 int hash_cnt=0;
00198 #endif 
00199 
00200 /*
00201  * Recherche d'un contexte, utilisation de façon implicite de sym_context
00202  * et de sym_hash.
00203  * C'est une procédure très critique qui doit être particulièrement optimisée
00204  */
00205 
00206 UINT ppm_worker::Context_Search(int order)  {
00207   UCHAR *sym;
00208   UINT i,p;
00209   NODE *n;
00210 #ifdef DEBUG   
00211   printf("Context_Search: o=%d\n",order);
00212 #endif
00213    
00214   p=hash_table[sym_hash[order]];
00215   sym=&sym_context[1];
00216 #ifdef STAT
00217   hash_nb++;
00218 #endif
00219   while (p<HASH_ADDRESS)  {
00220 #ifdef STAT
00221     hash_cnt++;
00222 #endif
00223     n=&node_heap[p];
00224     if (n->hdr.order==order)  {
00225       if (order==0) return p;
00226       i=0;
00227       while (sym[i]==n->hdr.sym[i]) {
00228         i++;
00229         if (i==order) return p;
00230       }
00231     }
00232     p=n->hdr.hash_next;
00233   }
00234   return HASH_ADDRESS;
00235 }
00236 
00237 /*
00238  * Cette macro est HORRIBLE mais permet de simplifier beaucoup le parcours
00239  * des listes de couples symbole,fréquence tout en ayant un code rapide.
00240  * Une alternative élégante mais lente aurait été de passer une fonction
00241  * en paramètre contenant le code à exécuter
00242  */
00243 
00244 #define SF_Read(n,p,code_to_execute) \
00245 {\
00246          UINT nb,i;\
00247          nb=(UINT)n->hdr.sf_max+1;\
00248    if (nb<=HDR_SFNB)  {\
00249       p=&n->hdr.sf.sf[0];\
00250    } else {\
00251       p=&node_heap[n->hdr.sf.l.sf_next].sf.sf[0];\
00252       while (nb>NODE_SFNB) {\
00253                                  for(i=0;i<NODE_SFNB;i++)  {\
00254                                                 code_to_execute;\
00255                                                 p++;\
00256                                  }\
00257                                  p=&node_heap[ *((USHORT *)p) ].sf.sf[0];\
00258                                  nb-=NODE_SFNB;\
00259       }\
00260    }\
00261    for(i=0;i<nb;i++)  {\
00262                         code_to_execute;\
00263       p++;\
00264    }\
00265 }
00266 
00267 
00268 /* 
00269  * Renormalisation d'un contexte, ie, division de toutes les fréquences 
00270  * par 2 et élimination des symboles de fréquence nulle  
00271  * Note: le contexte obtenu n'est jamais vide. 
00272  * Une amélioration prévue mais non implémentée serait de trier le contexte
00273  * dans l'ordre des fréquences décroissantes pour accélérer la recherche.
00274  * Les gains en vitesse seraient de toute façon assez faibles car les
00275  * contextes sont de toute façon à peu près triés vu leur méthode de 
00276  * construction: les caractères sont ajoutés à la fin de la liste 
00277  */
00278 void ppm_worker::Context_Renorm(UINT ctx) {
00279   NODE *n,*m;
00280   UINT a,b,c,i,freq_tot,sf_nb;
00281   SYMFREQ s,*p,tab_sf[SYM_NB];
00282          
00283 #ifdef DEBUG   
00284   printf("Context_Renorm: c=%d\n",ctx);
00285   Context_Print(ctx);
00286 #endif 
00287    
00288   n=&node_heap[ctx];
00289   freq_tot=0;
00290   sf_nb=0;
00291          
00292   SF_Read(n,p, {
00293     s=*p;
00294     s.freq=s.freq/2;
00295     if (s.freq!=0) {
00296       freq_tot+=s.freq;
00297       tab_sf[sf_nb]=s;
00298       sf_nb++;
00299     }
00300   } );
00301          
00302          
00303   /* libération des noeuds utilisés pour stocker les symboles */
00304   if (n->hdr.sf_max>=HDR_SFNB) {
00305     a=n->hdr.sf.l.sf_next;
00306     do {
00307       b=node_heap[a].sf.sf_next;
00308       Node_Free(a);
00309       a=b;
00310     } while (a!=NIL);
00311   }
00312                                  
00313   /* reconstruction de la liste des "sf_nb" symboles d'apres le tableau
00314    * "tab_sf"
00315    */ 
00316 
00317   n->hdr.sf_max=sf_nb-1;
00318   if (sf_nb<=HDR_SFNB)  {
00319     for(i=0;i<sf_nb;i++) n->hdr.sf.sf[i]=tab_sf[i];
00320   } else  {
00321     a=Node_Alloc();
00322     n->hdr.sf.l.sf_next=a;
00323     n->hdr.sf.l.freq_tot=freq_tot;
00324     m=&node_heap[a];
00325     i=0;
00326     c=0;
00327     while (1) {
00328       m->sf.sf[c]=tab_sf[i];
00329       i++;
00330       if (i==sf_nb) break;
00331       c++;
00332       if (c==NODE_SFNB)  {
00333         c=0;
00334         a=Node_Alloc();
00335         m->sf.sf_next=a;
00336         m=&node_heap[a];
00337       }
00338     }
00339     m->sf.sf_next=NIL;
00340   }
00341 
00342 #ifdef DEBUG
00343   Context_Print(ctx);
00344 #endif
00345 }
00346 
00347 
00348 /*
00349  * Mise à jour des index dans la table de hachage et des caractères du
00350  * contexte courant.
00351  * La fonction de hachage a été choisie de façon empirique en controlant
00352  * qu'elle donne en moyenne de bons résultats.
00353  */
00354 void ppm_worker::Hash_Update(int sym) {
00355   UINT i,k;
00356    
00357   for(i=ORDER_MAX;i>=2;i--) 
00358     sym_context[i]=sym_context[i-1];
00359   sym_context[1]=sym;
00360    
00361   for(i=ORDER_MAX;i>=2;i--) {  
00362     k=sym_hash[i-1];
00363     sym_hash[i]=( (k<<6)-k+sym ) & (HASH_SIZE-1);
00364   }
00365   sym_hash[1]=sym+1;
00366 }
00367 
00368 
00369 /****************************************************************************
00370  * Système d'exclusion des symboles 
00371  ****************************************************************************/
00372 
00373 
00374 /*
00375  * Remise à zéro du tableau d'exclusion des symboles 
00376  */
00377 void ppm_worker::Sym_ExcludeReset(void) {
00378   UINT i;
00379    
00380   sym_excl_code++;
00381   if (sym_excl_code==0)  {
00382     for(i=0;i<SYM_NB;i++) sym_excl[i]=0;
00383     sym_excl_code=1;
00384   }
00385 }
00386 
00387 
00388 /****************************************************************************
00389  * Initialisation et Libération mémoire 
00390  ****************************************************************************/
00391 
00392 /*
00393  * Initialisation des structures de données du compresseur/décompresseur
00394  * retourne 0 si tout va bien
00395  */
00396 int ppm_worker::PPM_Init(unsigned short NODE_NBMAX) {
00397   UINT i;
00398   node_heap= new NODE[NODE_NBMAX];
00399   hash_table= new USHORT[HASH_SIZE];
00400   if (node_heap==NULL || hash_table==NULL)  {
00401     if (node_heap!=NULL) delete [] node_heap;
00402     if (hash_table!=NULL) delete [] hash_table;
00403     return 1;
00404   }
00405   /* noeuds: tous vides */
00406   for(i=0;i<=(NODE_NBMAX-2);i++) node_heap[i].free_next=i+1;
00407   node_heap[NODE_NBMAX-1].free_next=NIL;
00408   node_free_first=0;
00409   node_free_last=NODE_NBMAX-1;
00410   node_free_nb=NODE_NBMAX;
00411    
00412   /* contextes */
00413   for(i=0;i<HASH_SIZE;i++) hash_table[i]=HASH_ADDRESS+i;
00414    
00415   /* cette initialisation n'est pas sûre mais simplifie beaucoup le code:
00416    * on suppose que le premier contexte sera alloué dans le noeud 0
00417    */
00418   ctx_first=0;
00419   ctx_last=0;
00420   ctx_nb=0;
00421    
00422   /* contexte courant */
00423   for(i=0;i<=ORDER_MAX;i++) sym_context[i]=0;
00424   for(i=0;i<=ORDER_MAX;i++) sym_hash[i]=0;
00425 
00426   /* système d'exclusion des caractères */
00427   sym_excl_code=0xFF;
00428          
00429   return 0;
00430 }
00431 
00432 /*
00433  * Fin de la compression/décompression: on libère la mémoire
00434  */
00435 void ppm_worker::PPM_End(void) {
00436   free(hash_table);
00437   free(node_heap);
00438 }
00439 
00440 /****************************************************************************
00441  * Décodage et décompression
00442  ****************************************************************************/
00443 
00444 /*
00445  * Décodage: cf Encode_NewSym
00446  */
00447 int ppm_worker::Decode_NewSym(void) {
00448   UINT i,freq_tot,freq_cum,f;
00449   UCHAR code;
00450          
00451   code=sym_excl_code;
00452   freq_tot=0;
00453   for(i=0;i<SYM_NB;i++) if (sym_excl[i]!=code) freq_tot++;
00454   f=arith.Arith_DecodeVal(freq_tot+SYM_SPECIAL_NB);
00455   if (f>=freq_tot) {
00456     /* cas d'un symbole spécial */ 
00457     arith.Arith_Decode(f,f+1,freq_tot+SYM_SPECIAL_NB);
00458     return SYM_NB+f-freq_tot;
00459   } else  {
00460     i=0;
00461     freq_cum=0;
00462     while (1)  {
00463       if (sym_excl[i]!=code)  {
00464         freq_cum++;
00465         if (freq_cum>f) break;
00466       }
00467       i++;
00468     }
00469     arith.Arith_Decode(freq_cum-1,freq_cum,freq_tot+SYM_SPECIAL_NB);
00470     return i;
00471   }
00472 }
00473 
00474 /*
00475  * Décodage: cf Decode_NoExclude
00476  */
00477 int ppm_worker::Decode_NoExclude(UINT ctx) {
00478   NODE *n;
00479   UCHAR code;
00480   UINT i,f,freq_tot,freq_cum,freq_sym,sf_nb;
00481   SYMFREQ *p,s;
00482          
00483          
00484   n=&node_heap[ctx];
00485   code=sym_excl_code;
00486          
00487   /* Calcul de la somme des fréquences des caractères */
00488   if (n->hdr.sf_max<HDR_SFNB)  {
00489     freq_tot=0;
00490     for(i=0;i<=n->hdr.sf_max;i++) freq_tot+=n->hdr.sf.sf[i].freq;
00491   } else  {
00492     freq_tot=n->hdr.sf.l.freq_tot;
00493   }
00494          
00495   /* décodage */
00496   sf_nb=(UINT) n->hdr.sf_max+1;
00497   f=arith.Arith_DecodeVal(freq_tot+sf_nb);
00498   if (f>=freq_tot)  {
00499     /* gestion du code ESCAPE */
00500                         
00501     /* marquage des caractères utilisés */
00502     SF_Read(n,p, { sym_excl[p->sym]=code; });
00503                                  
00504     /* décodage ESCAPE */
00505     arith.Arith_Decode(freq_tot,freq_tot+sf_nb,freq_tot+sf_nb);
00506     return SYM_ESCAPE;
00507   }
00508          
00509   /* recherche du caractère en calculant la fréquence */
00510   freq_cum=0;
00511   SF_Read(n,p, {
00512     s=*p;
00513     freq_cum+=s.freq;
00514     if (freq_cum>f) goto decode_sym;
00515   } );
00516          
00517  decode_sym:
00518 
00519   freq_sym=s.freq;
00520   p->freq=freq_sym+1;
00521   if (n->hdr.sf_max>=HDR_SFNB) n->hdr.sf.l.freq_tot=freq_tot+1;
00522 
00523   arith.Arith_Decode(freq_cum-freq_sym,freq_cum,freq_tot+sf_nb);
00524    
00525   /* test de la renormalisation */
00526   if (freq_sym==(RENORM_FREQSYM-1) || freq_tot>=RENORM_FREQTOT) { 
00527     Context_Renorm(ctx);
00528   }
00529   return s.sym;
00530 }
00531 
00532 
00533 /*
00534  * Décodage: cf Encode_Exclude
00535  */
00536 
00537 int ppm_worker::Decode_Exclude(UINT ctx) {
00538   UINT sf_nb,freq_sym,freq_cum,freq_tot,f;
00539   NODE *n;
00540   SYMFREQ s,*p;
00541   UCHAR code;
00542          
00543   n=&node_heap[ctx];
00544   code=sym_excl_code;
00545 
00546   freq_tot=0;
00547   sf_nb=0;
00548 
00549   SF_Read( n,p, {
00550     s=*p;
00551     if (sym_excl[s.sym]!=code) 
00552       {
00553         freq_tot+=s.freq;
00554         sf_nb++;
00555       }
00556   } );
00557          
00558          
00559   f=arith.Arith_DecodeVal(freq_tot+sf_nb);
00560          
00561   if (f>=freq_tot) {
00562                         
00563     /* ESCAPE */
00564                         
00565     SF_Read(n,p, { sym_excl[p->sym]=code; } );
00566                         
00567     arith.Arith_Decode(freq_tot,freq_tot+sf_nb,freq_tot+sf_nb);
00568                         
00569     return SYM_ESCAPE;
00570   } else  {
00571                         
00572     /* recherche du caractère */
00573                         
00574     freq_cum=0;
00575     SF_Read(n,p, {
00576       s=*p;
00577       if (sym_excl[s.sym]!=code)  {
00578         freq_cum+=s.freq;
00579         if (freq_cum>f) goto decode_sym;
00580       }
00581     } );
00582                         
00583   decode_sym:
00584                         
00585     /* incrémentation de la fréquence */
00586                         
00587     freq_sym=p->freq;
00588     p->freq=freq_sym+1;
00589     if (n->hdr.sf_max>=HDR_SFNB) n->hdr.sf.l.freq_tot++;
00590                         
00591     /* décodage du caractère */
00592                         
00593     arith.Arith_Decode(freq_cum-freq_sym,freq_cum,freq_tot+sf_nb);
00594    
00595     if (freq_sym==(RENORM_FREQSYM-1) || freq_tot>=RENORM_FREQTOT) { 
00596       Context_Renorm(ctx);
00597     }
00598                         
00599     return s.sym;
00600   }
00601 }
00602 
00603 
00604 /*
00605  * Décodage d'un symbole
00606  */
00607 int ppm_worker::PPM_Decode(void) {
00608   int i,order,sym;
00609   UINT ctx,ctx_tab[ORDER_MAX+1],ctx_last;
00610    
00611    
00612   /* recherche de l'ordre maximum */
00613 
00614   Sym_ExcludeReset();
00615   order=ORDER_MAX;
00616   ctx_last=NIL;
00617   while (1)  {
00618     ctx=Context_Search(order);
00619     ctx_tab[order]=ctx;
00620     if (ctx<HASH_ADDRESS)  {
00621       Context_MoveFirst(ctx); 
00622       if (ctx_last==NIL)
00623         sym=Decode_NoExclude(ctx);
00624       else
00625         sym=Decode_Exclude(ctx);
00626       if (sym!=SYM_ESCAPE) break;
00627       ctx_last=ctx;
00628     } 
00629     order--;
00630     if (order==-1)  {
00631       sym=Decode_NewSym();
00632       if (sym>=SYM_NB) return sym;
00633       break;
00634     }
00635   }
00636 
00637   for(i=order+1;i<=ORDER_MAX;i++) { 
00638     if (ctx_tab[i]>=HASH_ADDRESS) 
00639       Context_New(sym,i);
00640     else 
00641       Context_NewSym(sym,ctx_tab[i]);
00642   }
00643    
00644   Hash_Update(sym);
00645 
00646   return sym;
00647 }
00648 
00649 /*
00650  * Décompression: idem
00651  */
00652 
00653 #ifdef STAT
00654 
00655 /****************************************************************************
00656  * Statistiques 
00657  ****************************************************************************/
00658 
00659 
00660 void ppm_worker::PrintStat(void)  {
00661   fprintf(stderr,"free=%d ctx_nb=%d hash_moy=%0.2f\n",
00662           node_free_nb,ctx_nb,
00663           (float)hash_cnt/(float)hash_nb);
00664          
00665 }
00666 
00667 /*
00668  * Impression d'un caractère
00669  */
00670 void ppm_worker::Sym_Print(int c) {
00671   if (c>=32 && c<=126) printf("%c",c); else printf("\\%2X",c);
00672 }
00673 
00674 /*
00675  * Impression couple SYMFREQ
00676  */
00677 
00678 void ppm_worker::SF_Print(SYMFREQ s) {
00679   Sym_Print(s.sym);
00680   printf(":%d ",s.freq);
00681 }
00682 
00683 /*
00684  * Impression du contenu d'un contexte
00685  * utilisé pour les tests 
00686  */
00687 
00688 void ppm_worker::Context_Print(UINT c) {
00689   NODE *n;
00690   int i,sf_max,sf_nb,sf_freq;
00691    
00692   n=&node_heap[c];
00693    
00694   sf_max=n->hdr.sf_max;
00695   sf_nb=sf_max+1;
00696   if (sf_max>=2) sf_freq=n->hdr.sf.l.freq_tot;
00697   else  {
00698     sf_freq=0;
00699     for(i=0;i<=sf_max;i++) sf_freq+=n->hdr.sf.sf[i].freq;
00700   }
00701 
00702   printf("Ctx=%d: hash_n=%d ctx_p=%d ctx_n=%d o=%d sf_nb=%d sf_freq=%d\n",
00703          c,n->hdr.hash_next,n->hdr.ctx_prev,n->hdr.ctx_next,
00704          n->hdr.order,sf_nb,sf_freq);
00705   for(i=0;i<n->hdr.order;i++) Sym_Print(n->hdr.sym[i]);
00706   printf(": ");
00707   if (sf_max<=1) {
00708     for(i=0;i<=sf_max;i++) SF_Print(n->hdr.sf.sf[i]);
00709   } else  {
00710     n=&node_heap[n->hdr.sf.l.sf_next];
00711     i=0;
00712     while (1) {
00713       SF_Print(n->sf.sf[i]);
00714       if (sf_max==0) break;
00715       i++;
00716       sf_max--;
00717       if (i==NODE_SFNB)  {
00718         i=0;
00719         n=&node_heap[n->sf.sf_next];
00720       }
00721     }
00722   }
00723   printf("\n");
00724 }
00725 
00726 
00727 /*
00728  * Nombre total de contextes et nombre de contextes de longueur données.
00729  * Utilisé pour les statistiques
00730  */
00731 
00732 void ppm_worker::Context_Statistic(void) {
00733   UINT i,p;
00734   int tab[SYM_NB+1],tot,cnt;
00735    
00736   for(i=0;i<=SYM_NB;i++) tab[i]=0;
00737   tot=0;
00738    
00739   p=ctx_first;
00740   do {
00741     cnt=node_heap[p].hdr.sf_max+1;
00742     tab[cnt]++;
00743     tot++;
00744     p=node_heap[p].hdr.ctx_next;
00745   } while (p!=ctx_last);
00746    
00747    
00748   printf("Context_Statistic: ");
00749   for(i=1;i<=SYM_NB;i++)  {
00750     printf("%d:%d (%0.2f%%),",i,tab[i],(float)tab[i]/(float)tot*100.0);
00751   }
00752   printf("\n");
00753 }
00754 
00755 #endif
00756 

Generated on Sat Nov 5 16:16:56 2005 for OPIE by  doxygen 1.4.2