00001 #include <stdlib.h>
00002 #include <stdio.h>
00003 #include "arith.h"
00004 #include "ppm.h"
00005
00006
00007
00008
00009
00010
00011
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
00023
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
00040
00041
00042
00043
00044
00045
00046 void ppm_worker::Context_MoveFirst(UINT c) {
00047 NODE *ctx;
00048
00049 if (c!=ctx_first) {
00050 ctx=&node_heap[c];
00051
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
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
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
00076
00077
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
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
00106
00107
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
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
00127 ctx->hdr.hash_next=hash_table[sym_hash[order]];
00128 hash_table[sym_hash[order]]=ctx_first;
00129
00130
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
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
00202
00203
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
00239
00240
00241
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
00270
00271
00272
00273
00274
00275
00276
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
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
00314
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
00350
00351
00352
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
00371
00372
00373
00374
00375
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
00390
00391
00392
00393
00394
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
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
00413 for(i=0;i<HASH_SIZE;i++) hash_table[i]=HASH_ADDRESS+i;
00414
00415
00416
00417
00418 ctx_first=0;
00419 ctx_last=0;
00420 ctx_nb=0;
00421
00422
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
00427 sym_excl_code=0xFF;
00428
00429 return 0;
00430 }
00431
00432
00433
00434
00435 void ppm_worker::PPM_End(void) {
00436 free(hash_table);
00437 free(node_heap);
00438 }
00439
00440
00441
00442
00443
00444
00445
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
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
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
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
00496 sf_nb=(UINT) n->hdr.sf_max+1;
00497 f=arith.Arith_DecodeVal(freq_tot+sf_nb);
00498 if (f>=freq_tot) {
00499
00500
00501
00502 SF_Read(n,p, { sym_excl[p->sym]=code; });
00503
00504
00505 arith.Arith_Decode(freq_tot,freq_tot+sf_nb,freq_tot+sf_nb);
00506 return SYM_ESCAPE;
00507 }
00508
00509
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
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
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
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
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
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
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
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
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
00651
00652
00653 #ifdef STAT
00654
00655
00656
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
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
00676
00677
00678 void ppm_worker::SF_Print(SYMFREQ s) {
00679 Sym_Print(s.sym);
00680 printf(":%d ",s.freq);
00681 }
00682
00683
00684
00685
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
00729
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