KIỂM CHỨNG ĐOẠN CHƯƠNG TRÌNH KHÔNG CÓ VÒNG LẶP

Một phần của tài liệu Giáo trình kỹ thuật lập trình nâng cao (Trang 64 - 68)

LẶP.

Cho : P, Q là các tân từ trên các biến của chương trình , S là một lệnh tổ hợp từ các lệnh gán với cấu trúc điều kiện và tuần tự. Chứng minh đặc tả : { P } S { Q} đúng đầy đủ .

Ở đây vì mỗi lệnh chỉ được thi hành một lần nên tính dừng của đoạn lệnh S được suy ra từ tính dừng của lệnh gán mà luôn được xem là hiển nhiên . Vì vậy trong trường hợp này tính đúng có điều kiện trùng với tính đúng đầu đủ.

1) Bài toán 1 : S là dãy tuần tự các lệnh gán .

Ví dụ1 : Kiểm chứng tính đúng của đoạn lệnh hoán đổi nội dung 2 biến x và y a) {(x=xo) and ( y = yo ) }

t := x ; x := y ; y := t ; {(x=yo ) and (y = xo ) } Chứng minh

{(x = yo ) and ( t = xo) } y := t {(x = yo ) and ( y = xo ) } (a) // tiên đề gán {(y = yo ) and ( t = xo ) } x := y {(x = yo ) and ( t = xo ) } (b ) // tiên đề gán {(y = yo ) and ( t = xo ) } x := y ; y := t {(x = yo) and ( y = xo ) } (c) // a , b , luật tuần tự

{(y = yo ) and ( x = xo ) } t := x {(y = yo ) and ( t = xo ) } (d) // tiên đề gán ( (x = xo ) and (y = yo ) ) ≡ ( ( y = yo ) and ( x = xo ) } (e ) // giao hoán {( x = xo ) and (y = yo ) } t := x {(y = yo ) and ( t = xo ) } (g) // d ,e, luật hệ quả

Kỹ thuật lập trình nâng cao - 65 -

{(x = xo ) and ( y = yo ) } t := x ; x := y ; y := t {(x = yo ) and ( y = xo ) (h) // c ,g , luật tuần tự Ví dụ1 : Kiểm chứng tính đúng của đặc tả : { (m :: k=2*m) and (y * zk = c)} k := k div 2 ; z := z * z ; { y * zk = c} Chứng minh :

(a) {y * (z*z)k = c} z := z * z {y*zk = c} (tiên đề gán) (b) {y * (z*z)k div 2 = c} k := k div 2 {y*(z*z)k = c} (tiên đề gán) (c) {y * (z*z)k div 2 = c} k := k div 2 ; z := z*z {y*z)k = c} (a ,b , luật tuần tự) (d) (m :: k = 2*m) and ( y * zk = c ) ==> (y*z2m = c) and ( m = k div 2 )

==> y * (z*z)k div 2 = c c ,d , luật hệ quả suy ra ĐPCM.

Nhận xét :

Với dẫy tuần tự các lệnh gán, việc chứng minh {P} S1; ...;Sn {Q} thướng được bắt đầu từ lệnh cuối cùng, dùng tiên đề gán để được đkđ, rồi cứ thế lần ngược về đến S1.

{Pn} Sn {Q} (n) tìm Pn từ Sn ,Q và tiên đề gán {Pn-1 } Sn-1 {Pn } (n-1) tìm Pn-1 từ Sn-1 , Pn và tiên đề gán {Pn-1 } Sn-1 ; Sn {Q} luật về dãy lệnh tuần tự

... ...

{P1 } S 1 ;...; S n {Q} (1) sau n-1 lần tương tự như trên. Sau đó dùng các tính chất của dữ kiện chứng minh logic rằng : P ==> P1 (0)

Từ (1) , (0) ,dựa vào luật hệ quả ta có : {P} S1 ; ... ; Sn {Q} ( ĐPCM ) 2) Bài toán 2 :

a) Kiểm chứng đặc tả : {P} if B then S1 else S2 {Q} Với S1, S2 là nhóm các lệnh gán , B là biểu thức boolean. Cách chứng minh :

+ Bước 1 : Tìm P1, P2 thỏa : {P1} S1 {Q} (1a) {P2} S2 {Q} (1b)

+ Bước 2 : Chứng minh ( dùng các tính chất logic và đại số ) P and B ==> P1 (2a)

P and (not B) ==> P2 (2b)

+ Bước 3 : Dùng luật hệ quả suy ra :

{P and B} S1 {Q} ( 3a) // 1a ,2a , và luật hệ qủa {P and (not B)} S2 {Q} ( 3b) // 1b ,2b , và luật hệ qủa + Bước 4 : Dũng (3a) , (3b) , luật điều kiện suy ra :

Kỹ thuật lập trình nâng cao - 66 -

{P} if B then S1 else S2 {Q} ( ĐPCM )

b) Kiểm chứng đặc tả : {P} S0 ; if B then S1 else S2 {Q} (*) với S1, S2, S0 là dẫy các lệnh gán Ví dụ : Kiểm chứng đặc tả : {y > 0} x := y-1 ; if (y > 3) then x := x*x else y := y-1 {x >= y} Để khẳng định được (*) ta cần chỉ ra 1 khẳng định R mà : {P} S0 {R}

và {R} if B then S1 else S2 {Q} rồi dùng luật hệ quả để có (*)

Làm thế nào để tìm được R ? Do S1 và S2 là nhóm lệnh gán tuần tự nên ta có thể tìm được (bằng tiên đề gán và luật về dãy lệnh tuần tự ) U và V để :

{U} S2 {Q} và {V} S3 {Q} .

Dĩ nhiên ta muốn U và V là các điều kiện tổng quát nhất có thể (ở đây là yếu nhất). R được xây dựng thế nào từ U và V ? Khả năng tổng quát nhất cho R để sau khi điểm điều kiện B sẽ có được U hoặc V là : R ≡ (B ==> U) and (not B ==> V)

Như sau này sẻ chỉ ra U , V , R được xây dựng như vậy là yếu nhất (weakest precondition) để đạt được Q tương ứng với lần lượt các lệnh S1 , S2 và if B then S1 else S2 , và được ký hiệu là : WP(S2,Q) ,WP(S3,Q) và WP(if B then S2 else S3, Q) tương ứng. Ví dụ 1 : Kiểm chứng đặc tả : { y > 0 } x := y - 1 ; if ( y > 3 ) then x := x * x else y := y - 1 ; { x >= y } Trong ví dụ này : P là tân từ : ( y > 0 ) ; Q là tân từ : ( x >= y ) B là biểu thức boolean : ( y > 3 ) S0 là lệnh gán : x := y - 1 ; Do S1 và S2 là lệnh gán : x := x * x ; S2 là lệnh gán : y := y - 1 ; Ta có : {x2 >= y} x := x*x {x >= y} suy ra U ≡ WP( S1 , Q ) x≡ 2 >= y (a)

{x >= y-1} y := y-1 {x >= y} suy ra V ≡ WP( S2 , Q ) x >= y-1

Kỹ thuật lập trình nâng cao - 67 -

Đặt R (B ==> U) and (not B ==> V) ≡

≡ ((y > 3) ==> (x2 >= y)) and ((y <= 3) ==> (x >= y-1))

Ta chứng minh được dễ dàng.

R and (y>3) ==> (x2 >= y) (c) R and (not(y>3)) ==> (x >= y-1) (d) nên theo luật hệ quả

{R and y>3} S2 {x >= y} ( {R and B} S2 {Q} ) (e) {R and not(y>3)} S3 {x >= y} ( {R and (not B)} S3 {Q} ) (g) Theo luật về lệnh chọn

{R} if ( y>3) then x := x*x else y := y-1 {x >=y} (h) theo tiên đề gán.

{ ((y>3) ==> ((y-1) 2 >=y)) and ((y <=3) ==> ((y-1) >= (y-1))) } x := y -1

{ R } (i) Dễ kiểm chứng được

(y>3) ==> ((y-1) 2 >= y ≡ true (j) (y<=3) ==> (y-1) >= y-1 ≡ true (k) nên

(y >0) ==> ((y>3) ==>((y-1)2 >=y)) and ((y<=3) ==> ((y-1) >=(y-1))) (l) Theo luật hệ quả

{y > 0} x := y-1;

if (y>3) then x := x*x else y := y-1 { x >= y} (m) // ĐPCM

Ví dụ 2 : kiểm chứng đặctả : { true }

if ( i <= j) then if (j<k ) then m := k else m := j else if( i<k) then m := k else m := i {(m >= i) and (m >= j) and (m >= k)}

Đặt Q(m) ( m >= i) and (m >= j) and (m >= k) ≡ Ta có :

(a) {Q(i)} m := i {Q(m)} (tiên đề gán) (b) {Q(k)} m := k {Q(m)} (tiên đề gán)

Đặt R1 ((i < k) ==> Q(k)) and ( (i >= k) ==>Q(i)) ≡ dùng luật về lệnh chọn ta sẽ chứng minh được :

{R1} if ( i < k) then ... {Q(m)} (c)

Kỹ thuật lập trình nâng cao - 68 -

Ta có: {R2} if (j < k ) then ... {Q(m)} (d) Dùng biến đổi đại số và logic để chứng minh ( true and ( i <= j)) ==> R2 (e)

( true and ( i > j )) ==> R1 (g)

Từ c , d, e ,g , theo luật về lệnh chọn ta có ĐPCM. Nhận xét :

Để chứng minh đặc tả {P} S {Q} với S là tổ hợp lệnh gồm chỉ các lệnh gán và điều

kiện đúng đầy đủ ,ta thực hiện công việc xây dựng điều kiện đầu yếu nhất P1 của S ứng với Q , sau đó bước kiểm chứng cuối cùng chỉ đơn giản là chứng minh : P ==> P1. Công việc trên được trình bày dưới dạng một hàm đệ quy như sau :

function DKDYN (S : nhóm_lệnh ; Q : tân_từ ) : tân_từ ;

var t : câu lệnh ; begin

if (S <> rỗng ) then begin

t := lệnh_cuối(S); S := S – t ;

if ( t = lệnh_gán(x:=bt)) then DKDYN := DKDYN(S,Q( x=bt) )

else (* t là lệnh if *)

DKDYN := (điều_kiện(t)==>DKDYN(phần_đúng(t),Q)) and not (điều_kiện(t)==>DKDYN(phần_khong đúng(t),Q)) end

else DKDYN := Q end ;

Một phần của tài liệu Giáo trình kỹ thuật lập trình nâng cao (Trang 64 - 68)

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

(108 trang)