Giới thiệu BWT

Một phần của tài liệu các kỹ thuật kiểm thử đột biến và ứng dụng kiểm thử chương trình c (Trang 38 - 44)

Phép biến đổi Burrow-Wheeler không phải là một thuật toán nén dữ liệu, mà chỉ làm thay đổi cấu trúc dữ liệu, tạo dữ liệu đầu vào cho các thuật toán nén dữ liệu khác như RLE, hoặc có thể kết hợp với phương pháp MTF để đạt được hiệu quả nén cao hơn với các thuật toán nén Entropy.

Mục đích của BWT là nhóm các ký tự giống nhau ở gần nhau hơn, khối ký tự mới nhận được khi nén sẽ hiệu quả hơn, để thực hiện được điều này ta lấy ví dụ trên chuỗi ký tự S như sau:

Cho chuỗi ký tự S = “NUNANUNONG”, để đơn giản ta không xét đến dấu cách.

2.4.2 Mã hóa

1) Tạo ra các khối dữ liệu bằng cách hoán vị vòng tròn ký tự cuối cùng của khối lên đầu khối. Ta thu được ma trận X[n×n], mỗi hàng của ma trận là một hoán vị của S: X 0 1 2 3 4 5 6 7 8 9 0 N U N A N U N O N G 1 G N U N A N U N O N 2 N G N U N A N U N O 3 O N G N U N A N U N 4 N O N G N U N A N U 5 U N O N G N U N A N 6 N U N O N G N U N A 7 A N U N O N G N U N 8 N A N U N O N G N U 9 U N A N U N O N G N 2) Sắp xếp các dòng ma trận theo thứ tự tăng dần, ta có X 0 1 2 3 4 5 6 7 8 9 0 A N U N O N G N U N 1 G N U N A N U N O N

4 N O N G N U N A N U 5 N U N A N U N O N G 6 N U N O N G N U N A 7 O N G N U N A N U N 8 U N A N U N O N G N 9 U N O N G N U N A N

3) Tạo ra khối dữ liệu mới L là cột cuối cùng của ma trận. Giá trị D lưu trữ vị

trí ký tự đầu tiên của S, D là nguồn gốc để khôi phục L thành S

X F L 0 A N U N O N G N U N 1 G N U N A N U N O N 2 N A N U N O N G N U 3 N G N U N A N U N O 4 N O N G N U N A N U 5 N U N A N U N O N G 6 N U N O N G N U N A 7 O N G N U N A N U N 8 U N A N U N O N G N D 9 U N O N G N U N A N Nhận xét:

- L có thể được lưu trữ trong mảng một chiều:

0 1 2 3 4 5 6 7 8 9

L= N N U O U G A N N N

- Tương tự với F cũng là mảng một chiều nhận giá trị là cột đầu tiên của ma trận,

F được suy ra từ mảng L bằng cách sắp xếp L tăng dần:

0 1 2 3 4 5 6 7 8 9

F= A G N N N N N O U U

void bwt_encode ( FILE *in, FILE *out )

{ unsigned int i = 0, last_index = BWT_SIZE; while( 1 ) {

/* get bytes and save to buffer. */

nread=fread((unsigned char *)bwt_buf, 1, BWT_SIZE, in); if ( nread == 0 ) break;

/* write the size of the block read. */

fwrite( &nread, sizeof( unsigned int ), 1, out ); /* initialize index table. */

for ( i = 0; i < nread; i++ ) { index_table[i] = i;

}

/* sort the bwt buffer array; */

qsort( index_table, nread, sizeof(int),

(int (*)(const void *, const void *))bwt_comp); /* output Last column buffer. */

last_index = nread;

for ( i = 0; i < nread; i++ ){ if ( index_table[i] == 0 ){

putc( bwt_buf[ nread-1 ], out ); last_index = i;

}

else putc( bwt_buf[ index_table[i] - 1], out ); }

fprintf(stderr,"\n-[last index: %5d]- ", last_index); /* output index of the original string in Last. */ fwrite( &last_index, sizeof(unsigned int), 1, out ); }

}

int bwt_comp( unsigned int *a, unsigned int *b ) { register int a1 = *a, b1 = *b, tmp = a1;

if ( bwt_buf[a1] != bwt_buf[b1] ) {

if ( bwt_buf[a1] > bwt_buf[b1] ) return 1; else return -1;

} else {

!= bwt_buf[++b1 == nread? b1 = 0 : b1] ){ if (bwt_buf[a1] > bwt_buf[b1]) return 1; else return -1; } } while ( a1 != tmp ); } return 0; } 2.4.3 Giải mã

Mã hóa bằng BWT cho ta mảng L và giá trị D. Từ L ta có thể suy ra được F. Để có thể suy từ L ra S, ta phải tìm mối quan hệ giữa L và F. Với mỗi ký tự trong L ta đều suy ra ký tự tiếp theo của S từ F căn cứ vào chỉ số, bởi vì quá trình chuyển

đổi BWT là quá trình hoán vị vòng quanh S.

Giả sử ta biết ký tự si trong L có vị trí là k (si = L[k]), ta cũng biết ký tự tiếp theo trong S là si+1 = F[k]. Ta đã biết được si+1 thì cũng biết được si+2, tương tự như vậy ta sẽ suy ra được S. Hình 11 minh họa quá trình này.

Hình 11. Minh họa cách giải mã Burrows - Wheeler

Giá trị D cho ta biết ký tự đầu tiên của S trong L và ký tự tiếp theo của S trong F. Như vậy ta cần một mảng phụ để lưu trữ chỉ số của từng ký tự trong L khi sắp xếp. Ta định nghĩa mảng T để lưu trữ (Transformation vector).

F L

s3 s2

s2 s1

Minh họa ví dụ

L ban đầu L sau khi sắp xếp

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9

L= N N U O U G A N N N F= A G N N N N N O U U

T= 6 5 0 1 7 8 9 3 2 4 D

Hình 12 suy ra được S

Hình 12. Minh họa cách giải mã ví dụ

Bắt đầu từ ký tự đầu tiên có chỉ số D=8; s1=L[8] = “N”; Ký tự tiếp theo s2=F[8] = “U” = L[T[8]] = L[2];

Ký tự tiếp theo s3 = F[2] = “N” = L[T[2]] = L[0]; Ký tự tiếp theo s4 = F[0] = “A” = L[T[0]] = L[6];

Quá trình cứ tiếp tục cho đến khi ta có T[5] = D thì kết thúc, kết quả ta thu được là chuỗi “NUNANUNONG”.

void bwt_decode ( FILE *in, FILE *out ) { unsigned int i, findex, last_index;

unsigned int sum, temp; while ( 1 ) {

/* get the size of the block. */

F Index L T A 0 N 6 G 1 N 5 N 2 U 0 N 3 O 1 N 4 U 7 N 5 G 8 N 6 A 9 O 7 N 3 U 8 N 2 ←D U 9 N 4

/* get character input (the last column). */ nread = fread( bwt_buf, 1, nread, in ); if ( nread == 0 ) break;

/* get the last index "pointer." */

fread ( &last_index, sizeof(int), 1, in ); /* initialize frequency array. */

for ( i = 0; i < 256; i++ ) { freq[i] = 0;

}

/* ---- count frequency of characters. ---- */ for ( i = 0; i < nread; i++ ) {

freq[ bwt_buf[i] ]++; }

/* ---- cumulative sum. ---- */ sum = 0;

/* after the index_table is filled in,

the freq[] array will contain the cumulative sum for all bytes. */ for ( i = 0; i < 256; i++ ) {

if ( freq[i] ) {/* only if existent in the last column! */ temp = freq[i]; /* save. */

freq[i] = sum; /* the cumulative sum.*/ sum += temp; /*add the current byte's frequency.*/ }

}

/* ---- finally, fill in the index_table. ---- */ for ( i = 0; i < nread; i++ ) {

index_table[ freq[bwt_buf[i]]++ ] = i; }

/*NOTE: last_index is the row index of the original string in the *sorted* matrix (see gtbwt5.c).*/

findex = index_table[last_index];

/* output the bytes; reverse BWT. */ while ( nread-- ){

putc( bwt_buf[ findex ], out ); findex = index_table[ findex ]; }

} }

Một phần của tài liệu các kỹ thuật kiểm thử đột biến và ứng dụng kiểm thử chương trình c (Trang 38 - 44)

Tải bản đầy đủ (PDF)

(63 trang)