25/05/2018, 07:39

Kiểm chứng tính đúng có điều kiện

Xét bộ 3 gồm : đọan lệnh S, các tân từ trên các biến của chương trình (có thể bao gồm các biến giả) P, Q ( P mô tả điều kiện đầu , Q mô tả điệu kiện cuối ). Bộ 3 : { P } S { Q } tạo nên đặc tả đoạn lệnh S . Đặc tả : { P } S { ...

Xét bộ 3 gồm : đọan lệnh S, các tân từ trên các biến của chương trình (có thể bao gồm các biến giả) P, Q ( P mô tả điều kiện đầu , Q mô tả điệu kiện cuối ).

Bộ 3 : { P } S { Q } tạo nên đặc tả đoạn lệnh S .

Đặc tả : { P } S { Q } được gọi là thỏa đầy đủ ( đúng đầy đủ - đ đ đ ) nếu xuất

phát từ bất kỳ 1 trạng thái thỏa P thực hiện đoạn lệnh S thì việc xử lý sẻ dừng ở trạng thái thỏa Q .

Đặc tả : { P } S { Q } được gọi là thỏa có điều kiện ( đúng có điều kiện - đcđk )

nếu xuất phát từ bất kỳ 1 trạng thái thỏa P thực hiện đoạn lệnh S nếu việc xử lý dừng thì trạng thái cuối thỏa Q ( tính dừng của S chưa được khẳng định ).

Khẳng định { P } S { Q } diễn đạt tính đúng có điều kiện (condition

correctness) (tđcđk) của S. Tính đúng của S dựa trên đkđ P và đkc Q với giả định

rằng tính dừng của S đã có.

Ví dụ : a) { (x = xo ) and (y = yo ) } Nếu (x = xo ) và (y = yo ) trước khi

t := x t := x được thi hành

{( t = x = xo ) and (y = yo ) } Thì sau đó ( t = x = xo ) và (y = yo )

b) {( t = x = xo ) and (y = yo ) } Nếu (t = x = xo ) và ( y = yo) trước khi

x := y x := y được thi hành

{ (t = xo ) and (x = y = yo ) } Thì sau đó ( t = xo ) và ( x = y = yo )

c) { (t = xo ) and (x = y = yo ) } Nếu (t = xo ) và (x = y = yo ) trước khi

y := t y := t được thi hành

{( y = xo ) and (x = yo ) } Thì sau đó ( y = xo ) và ( x = yo )

Các phát biểu a, b, c là đúng theo cảm nhận của ta về lệnh gán.

d) { x > 0 } Nếu (x > xo ) trước khi

x := x-1 x := x-1 được thực hiện

{ x > 0 } Thì sau đó ( x > 0 )

Phát biểu d là sai vì có một trạng thái ban đầu x = 1 thoả P ( x > 0 ) nhưng sau

khi thi hành lệnh x := x -1 (x giảm 1) thì x = 0 không thoả Q ( x > 0 ) .

Để có thể thực hiện chứng minh hình thức về tính đúng của các đoạn chương trình, ta cần có những tiền đề mô tả tác động của các thao tác xử lý cơ bản (lệnh cơ bản ) của ngôn ngữ dùng viết chương trình ( ở đây là ngôn ngữ cốt lõi đã được giới thiệu ơ IV.3 ). Một hệ tiên đề có tác dụng như thế của Ca. Hoare , được trình bày dưới dạng một hệ luật suy diễn (inference rules ) được xét dưới đây .

Các luật hệ quả (Consequence rules)

a)

Nếu đkđ P mạnh hơn điều kiện Q .Tức là: P => Q hay { P } ⊆ { Q } ( tập hợp

các trạng thái thoả P là tập con của các tập trạng thái thoả Q ) và mỗi trạng thái thoả Q đều đảm bảo trạng thái sau khi thi hành S (với giả định S dừng) thoả R thì mỗi trạng thái thoả P đều đảm bảo trạng thái sau khi thi hành S (với giả định S dừng) thoả

R.

Kiểm chứng tđcđk đặc tả sau :

{ x = 3 } x := 5 ; y := 2 { x = 5, y = 2 }

Ta có : { true} x := 5 ; y := 2 { x = 5 ; y = 2 } (a) // tạm công nhận

và ( x = 3 ) => true (b) // hiển nhiên

Nên { x = 3 } x := 5 ; y := 2

Kiểm chứng tđcđk đặc tả sau :

{ x > 3 } x := x -1 { x > 0 }

Ta có : { x > 1 } x := x-1 { x > 0 }

và ( x > 3 ) => ( x > 1)

{ x = 5, y = 2 } // theo tiên đề (1a)

(a) //tạm công nhận

(b) // hiển nhiên

Nên { x > 3 } x := x -1 { x > 0 } // theo tiên đề (1a)

b)

Kiểm chứng tđcđk đặc tả sau :

{ true } x := 5 ; y := 2 { odd(x) and even(y) }

Ta có : { true } x := 5 ; y := 2 { (x = 5) , ( y = 2 ) } (a) // tạm công nhận

và ( (x = 5) and (y = 2)) => odd(x) and even(y) (b) // hiển nhiên

Nên { true } x := 5 ; y := 2 { odd(x) and even(y) } //theo (1b)

Kiểm chứng tđcđk đặc tả :

{ x > 1 } x := x -1 { x >= 1 }

Ta có : { x > 1 } x := x-1 { x > 0 } (a) // tạm công nhận

và ( x > 0 ) => ( x >= 1) // (b) // vì x là biến nguyên

Nên { x > 1 } x := x -1 { x >= 1 } // theo (1b)

Hai luật này cho phép liên kết các tính chất phát sinh từ cấu trúc chương trình với các suy diễn logic trên dữ kiện.

Từ (2 ) ta suy ra nếu trước lệnh gán x := bt ; trạng thái chương trình làm P(bt) sai

(thoả not P(bt) ) thì sau lệnh gán P(x) cũng sai (thỏa notP(x)).

Lệnh gán x := bt xoá giá trị cũ của x , sau lệnh gán x mang giá trị mới là trị của biểu thức bt , còn tất cả các biến khác vẫn giữ giá trị như cũ

Tính đúng có điều kiện của các đặc tả sau được khẳng định dựa vào tiên đề gán

a) { x = x } y := x { x = y }

b) { 0 <= s + t - 1 } s := s + t - 1 { 0 <= s }

c) { i = 10 } j := 25 { i = 10 }

Luật về dãy lệnh tuần tự ( Rules on Sequential Composition )

Giả định có tính dừng của S1 và S2, luật này phát biểu ý sau :

Nếu: 1. Thi hành S1 với đkđ P đảm bảo đkc R ( đặc tả { P } S1 { R } đ cđ k )

2. Thi hành S2 với đkđ R đảm bảo đkc Q ( đặc tả { R } S2 { Q } đ cđ k)

Thì : thi hành S ≡ S1 ; S2 với đkđ P đảm bảo đkc Q (đ ặc tả { P } S1 ; S2 { Q } đ cđ k )

Kiểm chứng tđcđk đặc tả :

{true} x := 5 ; y := 2 { x = 5, y = 2 }

Ta có : { 5 = 5 } x := 5 { x= 5}

true =>( 5 = 5 ) và ( x = 5) => ( (x = 5) and (2 = 2) )

{true} x := 5 {( x = 5) and ( 2 = 2) }

{ x = 5 , 2 = 2 } y := 2 {( x = 5) and ( y = 2) }

{true} x := 5 ; y := 2 { x = 5, y = 2 }

Luật về điều kiện (chọn) (Rule for conditionals)

(a) // tiên đề gán

(b) // hiển nhiên (c) //theo luật hệ qủa

(d) // tiền đề gán // theo luật tuần tự

Ý nghĩa luật này là :

Nếu có :

{ P and B }

S1

{ Q }

{ P and notB }

S2

{ Q }

Thì suy ra :

{ P }

if B then S1 else S2

{ Q }

+ Nếu xuất phát từ trạng thái thỏa P and B

thi hành S1 thì sẻ tới trạng thái thỏa Q

+ Nếu xuất phát từ trạng thái thỏa P and not B thi hành S2 thì sẻ tới trạng thái thỏa Q

Nếu xuất phát từ trạng thái thỏa P

thi hành lệnh if B then S1 else S2

thì sẽ tới trạng thái thỏa Q .

Kiểm chứng tđcđk đặc tả :

{ i> 0 } if ( i= 0 ) then j := 0 else j := 1 {j=1}

Ta có : ((i> 0) and (i = 0)) ≡ false (a) //hiển nhiên

{ (i> 0 ) and (i = 0)} j := 0 {j=1} (b) //{false} S { Q } đúng với ∀

S , Q

( (i> 0) and not(i = 0)) ≡ true (c) // hiển nhiên

{true } j := 1 { j=1 } (d) //tiên đề gán

{(i >0) and not(i = 0)} j := 1 {j=1} (e) // c,d ,luật hệ qủa

Từ b ,e và tiên đề 3.2a ta suy ra ĐPCM.

Kiểm chứng tđcđk đặc tả :

{i >= j - 1} if ( i > j) then j := j+1 else i := i+1 {i >= j}

Ta có : {i >= j+1} j := j+1 {i >= j} (a) //tiên đề gán

((i >= j-1) and (i > j)) ==> (i >= j+1) (b) // biến đổi với chú ý i , j

nguyên

{(i >= j-1) and (i > j)} j := j + 1 {i >= j} (c) // a,b ,luật hệ quả {i+1 >= j} i := i+1 {i >= j} (d) // tiên đề gán

((i >= j-1) and not(i > j)) ==> (i+1 >= j) (e) // biến đổi

{(i >= j-1) and not(i > j)} i := i + 1 {i >= j} (g) // d ,e , luật hệ quả) Từ c , g dựa vào 3.2a suy ra ĐPCM.

Kiểm chứng tđcđk đặc tả :

{true} if odd(x) then x := x+1 {even(x)}

Ta có : {even(x+1)} x := x+1 {even(x)} (a) //tiên đề gán

true and odd(x) ==> even(x+1) (b) // hiển nhiên

{true and odd(x)} x := x+1 {even(x)} (c) // a ,b , luật hệ quả true and not odd(x) ==> even(x) (d) // hiển nhiên

Từ (c) và (d) dựa vào 3.2b suy ra ĐPCM .

Luật về lệnh lặp While

Luật này nói rằng nếu I không bị thay đổi bởi một lần thực hiện lệnh S thì nó cũng không bị thay đổi bởi toàn bộ lệnh lặp While B do S. Với ý nghĩa này I được gọi là bất biến (invariant) của vòng lặp.

Chú ý rằng khẳng định : { P } while B do S { Q } thỏa dựa vào hệ luật Hoare

chỉ xác định tđcđk (conditionnal correctness). Để chứng minh tính đúng (correctness) thực sự ta cần bổ sung chứng minh lệnh lặp dừng.

của đặc tả : {i<=n} while (i < n ) do i := i+1 {i=n}

Xem I là ( i <= n ) thì :

{ I and ( i < n )} i := i+1 {I} (a) // dễ kiểm chứng

Nên {I} while ( i < n ) do i := i+1 { I and not(i<n)} (b) // luật 3.3

Mà I and not(i<n) ≡ (i <= n) and ( i >= n ) ==> i=n (c)

Từ b ,c , luật hệ qủa ta có ĐPCM.

của đặc tả :

{sum = 0 , i = 0 , n > 0}

while ( i <> n ) do begin

i := i+1 ; sum := sum+i // S

end ;

{sum = n * (n+1)/2} // tức sum

Ở đây : I là (sum = i*(i+1)/2 ) ; B ≡ ( i <> n )

Ta có :

{( sum = i*(i+1)/2 ) ,( i<>n)} i := i+1 ; sum := sum+i

tự { I } while B do S { I and not B }

( s = 0) and (i = 0) and (n >0) ==> s = i*(i+1)/2 ( s = i*(i+1)/2) and not(i<>n) ) ==> s=n*(n+1)/2 Từ b , c , d ta suy ra ĐPCM.

= 1 + 2 + ... .. + n

{sum = i*(i+1)/2}

(a) //tiên đề gán và tuần

(b) // a,và luật 3.3

(c) //hiển nhiên

(d) //hiển nhiên

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 đủ.

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

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ả

{(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 )

Bài toán 2 :

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 :

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

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.

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

(b)

Đặ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)

R and (not(y>3)) ==> (x >= y-1)

nên theo luật hệ quả {R and y>3} S2 {x >= y} (

{R and not(y>3)} S3 {x >= y}

Theo luật về lệnh chọn

(c)

(d)

{R and B} S2 {Q} ) (e)

( {R and (not B)} S3 {Q} ) (g)

{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

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)

Tương tự đặt R2 ≡ ( j<k) ==> ( Q(k) and (j >= k)) ==> Q(j)

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 ;

Bất biến

Một tính chất đặc thù của trí tuệ là nó thoát khỏi công việc mà nó đang thực hiện, khảo sát kết quả mà nó đã làm và luôn luôn tìm kiếm, và thường phát hiện được , các khuôn mẫu (Douglas R. Hofstadter).

Một bất biến là một tính chất không thay đổi tồn tại trong một khung cảnh, một sự kiện một quá trình thay đổi thường xuyên.

Một điều có vẻ nghịch lý là trong một thế giới, thay đổi và cần thiết phải thay đổi nhanh chóng, các bất biến lại có ý nghĩa rất quan trọng đối với chúng ta. Một em bé trong một nước nói tiếng Anh học cách thành lập dạng số nhiều của danh từ : dogs, cats, hands, arms ..., cách thành lập dạng quá khứ của động từ :

kicked, jumped, walked ... bằng học luật không đổi (thêm s, thêm ed), kèm theo

với việc học thuộc một số trường hợp ngoại lệ. Hãy tưởng tượng việc học sẽ khó như thế nào nếu không có các luật không đổi (bất biến ) này.

Việc nhận thức được các bất biến thường dẫn tới những lời giải đơn giản cho các bài toán khó.

Đầu óc con người dường như có một khả năng đặc biệt để nhận thức các bất biến hay các "khuôn mẫu".

Hãy quan sát 2 dãy các hình sau :

Hình kế tiếp trong mỗi dãy hình trên là gì ? Tính chất bất biến của mỗi dãy là gì ? (a) Lặp lại bộ 3 hình vuông, tròn, tam giác.

(b) Về dạng thì là sự lặp lại của cặp 2 hình vuông lớn và nhỏ. Về màu thì là sự lặp lại của một màu trắng và 2 màu sậm.

Trong lĩnh vực chương trình cho máy tính, ta cũng cần nhận thức các sự việc bằng cách phát hiện các bất biến. Đối với một chương trình, ta có nhiều lần máy tính thi hành nó, mỗi lần thi hành được gọi là một quá trình (process) và tác động trên các dữ

kiện khác nhau. Tính bất biến của các quá trình này chính là đặc tả của chương trình. Bên trong một chương trình có thể có các vòng lặp. Việc thực hiện vòng lặp làm biến thiên nhiều lần trạng thái các biến chương trình (các đối tượngdữ liệu ) , mà số lần biến thiên thường không biết trước được . Làm thế nào để hiểu được tác động của vòng lặp và đi đến chứng minh vòng lặp thực hiện một tính chất (giữ một bất biến) nào đó thể hiện bởi đặc tả của nó.

Việc nhận thức (tìm ra ) các tính chất bất biến của trạng thái chương trình trước và sau mỗi lần lặp có vai trò quyết định ở đây.

Với vòng lặp :

tg := 0 ;

i := 0 ;

while ( i <= n ) do begin

i := i + 1 ;

tg := tg + a[i] ; end ;

Tính chất bất biến ở đây là : bất chấp i, sau lần lặp thứ i, tg sẽ chứa tổng i phần tử đầu tiên của array a(a[1], a[2], ..., a[i]).

{} Tức là : tg = S(j: 1 <= j <=i : a[j]) = ∑1ia[j] size 12{ Sum cSub { size 8{1} } cSup { size 8{i} } {a [ j ] } } {}

Lý luận quy nạp và chứng minh bằng quy nạp.

Trong khoa học cũng như trong đời sống hàng ngày, người ta thường cần phải suy diễn từ các phát hiện riêng lẻ để đi đến các quy luật (bất biến) phổ dụng cho mọi( hay hầu hết) trường hợp có thể.

Quá trình mà con người xác lập được một tính chất bất biến từ một tập hợp các quan sát được gọi là suy diễn quy nạp.

Suy diễn quy nạp xuất phát từ quan sát và kết quả là cho ra các giả thuyết cần chứng minh.

Từ các quan sát : 1 = 1 = 12

1 + 3 = 4 = 22

1 + 3 + 5 = 9 = 32

1 + 3 + 5 + 7 = 16 = 42

Bằng quy nạp người ta đặt giả thuyết : 1 + 3 + ... (2*n - 1) = n2

Ta có thể thử lại giả thuyết này với n = 5, 6... . Tuy nhiên, để khẳng định rằng giả thuyết đúng với mọi n, ta cần có chứng minh. Phưong pháp chứng minh thường dùng trong trường hợp này là chứng minh bằng quy nạp.

Nguyên lý quy nạp toán học đơn giản .

Để chứng minh một tân từ P(n) phụ thuộc vào số tự nhiên là đúng với mọi n . Ta cần chứng minh 2 điều sau :

(i) P(0) là đúng

(ii) Nếu P(n) được giả định là đúng thì sẽ suy ra P(n+1) cũng đúng.

Khẳng định P(0) được gọi là cơ sở (basis) và bước chứng minh (ii) là bước quy

nạp (inductive step). Khi có được 2 điều (i) và (ii), dựa vào nguyên lý quy nạp toán học, ta kết luận rằng P(n) đúng với mọi số tự nhiên n .

Trên thực tế nguyên lý trên thường được áp dụng hơi khác.

+ Để chứng minh P(n) đúng với mọi số tự nhiên n >= m thì cơ sở của chứng

minh quy nạp là P(m) chứ không phải P(0).

+ Để chứng minh P(n) đúng với mọi số tự nhiên n thoả m <= n<= p ta chứng

minh :

(i) P(m) đúng

(ii) Nếu m <= n < p và P(n) đúng thì P(n+1) đúng.

(i) Cơ sở : P(1) chính là 1 = 12 đúng

(ii) Giả sử P(n) đúng, tức là 1 + 3 + ... (2*m - 1) = n2

thì ta sẽ có :

1 + 3 + .... + ( 2*(n+1)-1 ) = (1+3+....+(2*n -1)) + (2*(n+1)-1)

= n2 + 2*(n+1) - 1

= (n+1)2

Vậy P(n+1) đúng .Dựa vào (i) và (ii), ta kết luận P(n) đúng với mọi số tự nhiên n >=1 theo nguyên ly quy nạp toán học.

Nguyên lý quy nạp mạnh (Strong induction principle)

Để chứng minh P(n) đúng với mọi số tự nhiên n ta cần chứng minh hai điều sau : (i) P(0) đúng

(ii) Nếu giả định là P(0), P(1), ... . P(n) đều đúng thì P(n+1) cũng đúng

Cũng như nguyên lý quy nạp đơn giản, người ta có thể dùng các biến dạng của nguyên lý quy nạp mạnh để chứng minh P(n) đúng với mọi số tự nhiên n >= m

cho trước hay với mọi số tự nhiên n mà m < n <= p với m,p cho trư?c.

Kiểm chứng chương trình có vòng lặp while.

Dạng tổng quát của bài toán .

Cho W là một lệnh lặp while B do S và cặp đkđ P, đkc Q.

Ta cần phải chứng minh rằng : đặc tả { P } W { Q } được thỏa đầy đủ . Để chứng minh W thoả đầy đủ đặc tả P,Q ta cần chỉ ra 2 điều :

(i) P bảo đảm W dừng,tức là xuất phát từ trạng thái bất kỳ thoả P,thì hành W thì W sẽ dừng sau một thời gian hữu hạn ( sau khi thực hiện hưu hạn lần lệnh S ở thân vòng lặp W thì B sẻ có gía trị false ).

(ii) {P} W {Q} - Đúng có điều kiện ( xuất phát từ trạng thái thỏa P sau khi thi hành W nếu W dừng thì sẻ đạt tới trạng thái thỏa Q ).

Để chứng minh (ii) ta có thể dùng hệ luật Hoare mà chủ yếu là phải phát hiện được bất biến I.

Để chứng minh (i) W dừng ta cần dựa trên các biến bị thay đổi trong vòng lặp thường dựa vào một hàm f của các biến chương trình nhận gía tri nguyên và chỉ ra rằng :

(α) Ở đầu mỗi lần lặp ( B thoả ) thì f > 0 .

Tức là : I and B ==> f > 0

(β) Mỗi lần thực hiện S sẽ làm giảm thực sự giá trị của f.

Nếu (α) và (β) thoả thì S không thể lặp vô tận được (vì sau hưu hạn lần thì B sẻ nhận gía trị false ).

Chỉ ra các vòng lặp sau đây dừng : {n >= 0}

k := n ;

while (k <>0 ) do begin {k > 0} k := k-1 ;

r := 2*r + p[k];

if (r >= q) then r := r - q

end ;

vì bất biến {k > 0} luôn được giữ đúng ở đầu vòng lặp. Ở đây hàm f chính là

bằng k. f giảm sau mỗi lần lặp ( vì k := k - 1 ). Vậy vòng lặp dừng .

{x >= 0 ; y >= 0}

a := x ; b := y ;

while (a <>b) do

{max(a,b) > 0}

if (a>b ) then a := a - b else b := b - a

Ở đây hàm f = max(a,b). Ta luôn có bất biến max(a,b) > 0 ở đầu vòng lặp, f giảm sau mỗi lần lặp.

Các ví dụ về chứng minh chương trình có vòng lặp .

Xét đặc tả đoạn chương trình tính tích 2 số nguyên A và B với B >= 0 bằng phép cộng :

{ B >= 0 } R := 0 ;

X := B ;

while (X <>0 ) do begin

R := R + A ;

X := X - 1 ; end ;

{ R = A*B }

đkđ P ≡ B >= 0

đkc Q ≡ R = A * B

Bước 1: của đặc tả {P} S {Q}

+ Kiểm chứng đoạn lệnh trước vòng lặp : Chứng minh đặc tả sau đúng .

{ B >= 0 }

R := 0 ; (*)

X := B ;

{X = B , R = 0, B >= 0 }

Ta có :

{0 = 0 , B >= 0} R := 0 {R = 0 , B >= 0} (1) tiên đề gán

{0 = 0 , B >= 0} ⇒ { B >= 0} (2) hiển nhiên

{B >= 0} R := 0 {R = 0, B >= 0} (3) luật hệ quả dựa vào (1),(2)

{B = B , R = 0 , B >= 0} X := B {X = B , R = 0 , B >= 0} (4) tiên đề gán

{B =B , R =0 , B >= 0} ⇒ { R = 0 , B >= 0 } (5) hiển nhiên

{R = 0 , B >= 0} X := B {X := B , R = 0 , B >= 0} (6) Luật hệ quả dựa vào

(4),(5)

{B >= 0} X := 0 ; X :=B {X = B , R = 0 , B >= 0} (7) luật tuần tự dựa vào (3),(6).

Như vậy với điều kiện đầu B >= 0 thì sau khi thực hiện xong 2 lệnh khởi động, ta có khẳng định X = B, R = 0, B >= 0 đặc tả (*) đúng .

+ Kiểm chứng vòng lặp :

- Phát hiện được bất biến của vòng lặp.

Bất biến ở đây là : “ số lần X bị giảm đi chính là số lần A được cộng vào R “ Tức là : I ≡ ( R = A*(B-X) ) and ( X >= 0 )

Khẳng định (X >= 0 ) được thêm vào để chứng minh vòng lặp dừng. - Chứng minh I là bất biến của vòng lặp :

{( R + A = A*B - A*X + A ) and ( X >0 )} R := R + A

{(R = A*B - A*X + A ) and ( X > 0 )} (8) tiên đề gán

{ ( R = A*(B - X)) and ( X > 0 )}

R := R + A

{ ( R = A*B - A*X + A ) and ( X > 0 )} (9) biến đổi từ (8)

{ ( R = A*B - A*X + A ) and ( X > 0 )} ≡ { ( R = A*(B -(X - 1)) ) and ( (X - 1 ) >= 0 )}(10)

{ ( R = A*(B -(X - 1)) ) and (( X - 1 ) >= 0 )}

X := X - 1

{( R = A*(B - X)) and ( X>=0 ) }

{( R = A*B - A*X + A) and (X > 0)}

X := X - 1

{( R = A*(B - X ) ) and ( X >= 0 )} {(R = A*(B -X )) and ( X > 0 )}

R : = R+A ; X := X - 1

{( R = A*(B - X )) and ( X >= 0 )}

(11) tiên đề gán

(12) luật hệ quả

(13) luật tuần tự dựa vào (9 ),(12)

{(R = A*(B - X )) and (X >= 0 ) and (X<>0)} ==> {(R =A*(B - X )) and (X >0 )}(14)

{(R = A*(B - X )) and (X >= 0) and (X<>0)}

R := R+A ; X := X-1

{(R = A*(B - X )) and (X >= 0)} (15) luật hệ quả dựa vào (13 ),(14)

Hay {I and C} R := R + A ; X := X - 1 {I}

với C là điều kiện vòng lặp X<>0

Do luật lặp ta có :

{I} while ... {I and not C}

(X=B) and (R=0) and (B>=0) ==> (R=A*(B-X)) and (X>=0) (16) Kết hợp 15,16 và 5 dùng luật hệ quả rồi luật tuần tự, ta có : {X=B and R=0 and B>=0} while ... {I and notC} (17) {B>=0} R:=0 ; X:=B ; while ... {I and notC} (18) Ở đây I and not C ≡ ( R = A*(B-X)) and (X >= 0 ) and (X = 0)

mà ( R = A*(B-X)) and ( X >= 0) and (X=0) ==> R=A*B Dùng luật hệ quả ta có đpcm

Bước 2 : Chứng minh tính dừng : Đặt f = X, ta có :

(i) I and C ≡ ( R = A*(B-X) ) and ( X >= 0) and (X<>0 ) => X > 0 => f > 0

(ii) Mỗi lần lặp, f bị giảm một đơn vị. Vậy vòng lặp phải dừng.

Từ (i) và (ii) ta kết luận được tính dừng từ bước 1 và bước 2 suy ra tính đúng đầy đủ của đoạn chương trình đối với P,Q.

Nhận xét từ chứng minh trên :

+ Đối với dãy các lệnh gán, nên phát xuất quá trình suy diễn từ điều kiện cuối. + Đối với vòng lặp cần xác định đúng bất biến của nó.

Chú ý : Ta có thể kiểm chứng tđcđk của đoạn chương trình trên bằng cách:

- Xây dưng một lư?c đồ chứng minh hợp lý bằng cách dựa vào các tiên đề và càc khẳng định đã có trước đó chèn bổ sung các khẳng định trung gian ở những điểm khác nhau trong đoạn chương trình .

{P } ≡ { B >= 0 } (0)

{(0 = A*(B - B )) and (B >= 0 )} (3)

R := 0 ;

{(R = A*(B - B )) and (B >= 0)} (2)

X := B ;

{I } ≡ {( R = A*(B - B )) and ( X >= 0 )} (1a)

while (X <>0 ) do begin

{I and C } ≡ {( R = A*(B - X )) and (X >= 0) and (X<>0)} (1b)

{(R + A = A*(B -(X - 1 )) and ( (X -1 ) >= 0)} (5)

R := R+A ;

{( R = A*(B -(X - 1 )) and ( (X - 1 ) >= 0)} (4)

X := X - 1 ;

{I } ≡ {(R = A*(B - X)) and ( X >= 0 )} (1d)

end

{I and notC } ≡ {( R = A*(B - X ) ) and (X >= 0) and not(X <> 0)} (1c)

{Q } ≡ { R = A*B} (6)

Lý lẽ để bổ sung là :

(1a) do phát hiện được bất biến I

(1b),(1c),(1d) dựa vào tiên đề về lệnh lặp xuất phát từ I 2, 3 dựa vào tiên đề gán xuất phát từ (1a)

4, 5 dựa vào tiên đề gán xuất phát từ (1d)

Các cặp khẳng định đi liền nhau là các điều kiện cần kiểm chứng :

(0) ==> (3) : ( B >= 0 ) ==>( (0 = A * (B-B)) and (B >= 0 ) )

(1b) ==> (5) : (( R = A*(B - X )) and (X >= 0) and (X<>0)) ==>

((R + A = A*(B -(X - 1 )) and ( (X -1 )

>= 0))

(1c) ==> (6) : ( (R = A*(B-X)) and (X >= 0) and (X = 0)) ==> ( R=A*B )

Dễ dàng chứng minh các điều trên.

0