1 . Ý chung .
Để kiểm chứng tính đúng của một đoạn chương trình chúng ta cần thực hiện các việc sau :
+ Xây dựng lược đồ chứng minh hợp lý xuất phát từ đặc tả đoạn chương trình ( khẳng định dạng {P} S {Q} về tđcđk của cả đoạn chương trình S ). + Chưng minh tính đúng của lược đồ chứng minh đã xây dựng.
( Chứng minh tính đúng của mọi đặc tả trung gian dạng {Pi} Si {Qi} xuất hiện trong lược đồ , chứng minh các cặp khẳng định đứng liền nhau trong lược đồ dạng {Pi} { Ri} đều hợp lý tức là thỏa hệ thức Pi ==> Ri ) .
Trong 2 công việc trên thì việc xây dựng lược đồ chứng minh hợp lý là việc chiếm nhiều thời gian và công sức .
Việc xây dựng lược đồ chứng minh hợp lý sẻ khác nhau phụ thuộc vào cấu trúc của lệnh S song thường được tiến hành theo 2 bước sau :
- Bước 1 : Từ đặc tả xây dựng lược đồ chứng minh chi tiết bằng cách dựa vào các luật của hệ Hoare đưa vào các khẳng định trung gian .
- Bước 2 : Từ lược đồ cm chi tiết xây dựng lược đồ cm hợp lý bằng cách dựa vào các luật của hệ Hoare bỏ đi các khẳng định trung gian ở những nơi không quan trọng ( ở những khẳng định trung gian mà tính đúng của nó là rõ ràng và ta dễ dàng khôi phục nó ) . Giữ lại những khẳng định trung gian nào trong lược đồ cm hợp lý là một trong những nghệ thuật của người xây dựng lược đồ )
2. Thực hiện kiểm chứng trong trường hợp S là một dãy lệnh tuần tự . - Đặc tả : { P } S1 ; S2 ; . . . ; Sn { Q }
- Xây dựng lược đồ cm hợp lý :
+ Xây dựng lược đồ cm chi tiết : áp dụng liên tục các tiên đề gán (mục II.4.3) từ lệnh cuối ( bắt đầu từ cặp S , Q ).
Ví dụ : kiểm chứng đặc tả sau :
{even(k) and (0 < k ) and (y*zk = xn )} (đcđ)
k := k div 2 ; (6.1) z := z*z ;
{(0 <= k ) and (y * zk ) = xn )} (đkc ) Ta có : {even(k) and (0 < k ) and (y*zk = xn )} (đcđ) {(0 <= k div 2 ) and ( y * ( z * z ) k div 2 = xn ) (2)
k := k div 2 ; (6.2 ) {(0 <= k) and ( y * ( z * z ) k = xn ) (1) z := z*z ;
{(0 <= k ) and (y * zk ) = xn )} (đkc )
Ta có (6.2) là một lược đồ chứng minh chi tiết nó chứa tất cả các chi tiết cần thiết để xây dựng một chứng minh về tđcđk của đặc tả (6.1)
- Xây dựng lược đồ cm hợp lý : Dựa vào luật tuần tự bỏ đi khẳng định (1) ta có : {even(k) and (0 < k ) and (y*zk = xn )} (đcđ)
{(0 <= k div 2 ) and ( y * ( z * z ) k div 2 = xn ) (2)
k := k div 2 ; (6.3 ) z := z*z ;
{(0 <= k ) and (y * zk ) = xn )} (đkc ) (6.3) là lược đồ cm hợp lý .
- Chứng minh tính đúng :
+ Chứng minh tính đúng của đặc tả trung gian :
{(0 <= k div 2 ) and ( y * ( z * z ) k div 2 = xn ) (2) k := k div 2 ; z := z*z ; (6.4) {(0 <= k ) and (y * zk ) = xn )} (đkc ) Tính đúng của đặc tả 6.4 được bảo đảm dựa vào cách xây dựng . + Kiểm chứng tính hợp lý của hai khẳng định đi liền nhau :
{ even(k) and ( 0 < k ) and (y * zk ) = xn ) } { ( 0 <= k div 2 ) and (y*(z*z)k div 2 = xn ) Thực vậy :
even(k) and ( 0 < k ) and (y * zk = xn ) ==> (0 <= k div 2 ) and (y*(z*z)k div 2 = xn
)
được suy ra từ tính chất đại số và logic .
Chú ý : Để tăng tính hình thức của qúa trình xây dựng lược đồ người ta thường đưa vào các cách viết hình thức . Như ở ví dụ trên bằng cách viết lại điều kiện cuối cùng ký hiệu sau : I(z,k) ( 0 <= k ) and (y*z≡ k = xn )
Như vậy (6.2) có thể viết thành :
{even(k) and (0<k) and I(z,k)}
{I(z*z,k div 2 )} (6.3) k := k div 2 ; {I(z*z,k )} z := z*z ; {I(z,k)} Lược đồ cm hợp lý (6.4) có dạng : {even(k) and (0 < k) and I(z,k)}
{I(z*z,k div 2 )} (6.4) k := k div 2 ;
z := z*z ; {I(z,k)}
Điều kiện cần kiểm chứng là : even(k) and (0 < k ) and I(z,k)} ==> I(z*z , k div 2)
Đây chỉ là cách nói hình thức của sự kiện là (z*z)k div 2 = zk khi k là số nguyên chẵn. Điều này là mấu chốt để hiểu được tác động của hai lệnh gán.
3. Thực hiện kiểm chứng trong trường hợp S là lệnh điều kiện .
Khi đoạn chương trình chứa câu lệnh điều kiện thì ta thêm các khẳng định trung gian vào phần lệnh điều kiện dựa vào các luật về cấu trúc điều kiện.
Từ đặc tả có dạng :
{P} if B then S1 else S2 {Q} Ta xây dựng lược đồ dạng :
{P} if B then {P and B} S1 {Q} else {P and not B} S2 {Q} còn với đặc tả tương ứng lệnh điều kiện không có phần else {P} if B then S {Q}
thì ta cứ xem như nó có một phần else rỗng và lđcm tương ứng là : {P} if B then {P and B} S {Q}
else {P and not B} {Q}
Chú ý là cặp {P and not B} {Q} liên tục chính là một đkckc P and not B ==>Q Ví dụ : Kiểm chứng tính đúng đặc tả :
{ ( k > 0 ) and (y*zk = xn ) } if even(k) then begin
k := k div 2 ; z := z*z ; end else begin k := k -1 ; y := y*z ; end { ( k >= 0 ) and (y*zk = xn ) }
Bằng cách đặt I(y,z,k) ( k >= 0 ) and (y*z≡ k = xn ) Ta có lđcm :
{( k > 0 ) and I(y,z,k)} if even(k) then begin
{even(k) and ( k > 0 ) and I(y,z,k)} k := k div 2 ;
z := z*z ; {I(y,z,k)} end else begin
{(not even(k)) and ( k > 0 ) and I(y,z,k)} k := k -1 ;
y := y*z ; {I(y,z,k)} end
4. Trường hợp đoạn chương trình S có chứa lệnh lặp while B do S - Cách thứ nhất (dựa vào hệ toán tử Dijkstra) :
+ Xây dựng WP(while B do S , Q )
+ Chèn khẳng định { WP(while B do S , Q ) vào trước vòng lặp - Cách 2 (dựa vào các hệ luật Hoare ) :
+ Phát hiện bất biến I của vòng lặp
+ Chèn bất biến I vào lược đồ theo luật lặp như sau : {(Invariant) I}
while B do {I and B} S {I} {I and not B } {Q}
Điều kiện cần kiểm chứng duy nhất là : I and not B ==> Q.
Chú ý : Nếu xây dựng lược đồ dựa vào hệ luật Hoare thì ta còn phải kiểm chứng tính dừng của vòng lặp .
{ 0 <= n } y := 1 ; z := x ; k := n ; while (0 <> k ) do begin k := k -1 ; y := y*z end {y = xn }
Biết bất biến vòng lặp là : I(y,z,k) ≡ ( k >= 0 ) and (y*zk = xn ) Ta xây dựng lđcm theo các bước sau :
+ Chèn I(y,z,k) vào vòng lặp {0 <= n} y := 1 ; z := x ; k := n ; {(Invariant ) I(y,z,k)} while ( k <> 0 ) do begin {I(y,z,k) and (k <> 0 )} k := k -1 ; y := y*z ; {I(y,z,k)} end
{I(y,z,k) and not(k <> 0 )} {y = xn }
+ Dùng tiên đề gán ta đưa vào các khẳng định trung gian {0 <= n} {I(1,x,n)} y := 1 ; {I(y,x,n)} z := x ; {I(y,z,n)} k := n ; {(Invariant ) I(y,z,k)} while (0 <> k ) do begin {I(y,z,k) and (k <> 0 )} { I(y*z ,z ,k -1) } k := k -1 ; { I(y*z ,z ,k) } y := y*z ; {I(y,z,k)} end {I(y,z,k) and (k = 0 )}
{y = xn }
+ Dựa vào luật tuần tự bỏ đi các khẳn định trung gian {0 <= n} {I(1,x,n)} y := 1 ; z := x ; k := n ; {(Invariant ) I(y,z,k)} while (0 <> k ) do begin {I(y,z,k) and (k <> 0 )} { I(y*z ,z ,k -1) } k := k -1 ; y := y*z ; {I(y,z,k)} end {I(y,z,k) and (k = 0 )} {y = xn }
Ba điều kiện cần kiểm chứng là :
+ Phần chuẩn bị trước vòng lặp : (0 <= n ) ==> I(1,x,n) + Phần kết thúc vòng lặp : I(y,z,k) and (k = 0 ) ==> y = xn . + Phần trong vòng lặp : I(y,z,k) and (k <> 0 ) ==> I(y*x,z,k-1) Thế I(y,z,k) ≡ ( k >= 0 ) and (y*zk = xn ) tá có ba đckc là :
(Phần chuẩn bị) : ( 0 <= n ) ==> (1*xn = xn ) and (0 <= n ) ( hiển nhiên )
(Phần kết thúc lặp) : ( y * zk = xn ) and (0 <= k ) and (k = 0 )==> y = xn (hiển nhiên )
(Phần thân vòng lặp) : ( y * zk = xn ) and (0 <= k ) and (k <> 0 )
==> ((y*z)*zk-1 = xn ) and (0 <= k -1) (hiển nhiên )