Thuật toán xây dựng ôtômat hợp song song

Một phần của tài liệu (LUẬN văn THẠC sĩ) phân tích, thiết kế và cài đặt kiểm chứng một hệ thời gian thực (Trang 26)

Chương 2 CÁC CÔNG CỤ ĐẶC TẢ

3.1. Các thuật toán

3.1.1. Thuật toán xây dựng ôtômat hợp song song

Bài toán: Cho một hệ các ôtômat Ai = (Li, l0i, i, Xi, Ii, Ei), i = 1,2,3,… Hãy xây dựng ôtômat hợp song song đạt được từ các ôtômat thành phần Ai.

Ý tưởng thuật toán: thuật toán được xây dựng theo kỹ thuật duyệt đồ thị theo

chiều sâu. Thuật toán gồm 2 hàm, hàm 1 createOtomatParallelFrom2Otomat(A1, A2)

xây dựng ôtômat hợp song song đạt được từ 2 ôtômat bất kỳ, hàm 2

createOtomatParallel() sẽ gọi hàm createOtomatParallelFrom2Otomat(A1, A2) để tạo

ra một ôtômat hợp song song đạt được từ n > 1 ôtômat thành phần.

Hàm createOtomatParallelFrom2Otomat(A1, A2) xây dựng ôtômat hợp song

song đạt được từ 2 ôtômat bất kỳ A1, A2 được xây dựng theo kỹ thuật duyệt đồ thị theo chiều sâu đồng thời đối với 2 ôtômat như sau:

Bước 1: Ban đầu khởi tạo các thành phần của ôtômat hợp song song A = (L, l0,

, X, I, E) như sau: L = , E = , I = ,  = , X = X1  X2, l0 = {l01, l02}.

Bước 2: Xuất phát từ tập các đỉnh xuất phát của ôtômat thành phần A1, A2: l0 = {l01, l02}, và khi đó ta có L = { l0}.

Bước 3: Với mỗi đỉnh li = {li1, li2} L, nếu tồn tại phép chuyển ei= < li,i,ai,λi, li’>. Nếu ei là phép chuyển đồng bộ (tức ei E1 và ei E2) thì li’ = {li’1, li’2} thỏa mãn 2 điều kiện I(li’) = I(li’1)  I(li’2) ≠  và i= i1∩ i2 ≠ . Nếu ei là phép chuyển cục bộ (tức hoặc ei  E1 hoặc ei  E2) thì li’ = {li’1, li2} (hoặc li’ = {li1, li’2}), I(li’) = I(li’1) (hoặc I(li’) = I(li’2)) và i= i1(hoặc i= i2).

Khi đó nếu li’  L thì thêm li’ vào L, nếu phép chuyển ei E thì thêm ei vào E. và ưu tiên phép chuyển đồng bộ trước. Tức là nếu ailà nhãn (hành động) đồng bộ thì phải thực hiện phép chuyển đồng bộ.

Bước 4: Thuật toán dừng khi không còn đỉnh mới để di chuyển nữa.

Để cài đặt thuật toán này ta sử dụng một ngăn xếp S để lưu lại đường đi, mỗi phần tử S gồm 2 thành phần:

1) Thành phần 1: Tên vị trí x và tập Ax các đỉnh kề của đỉnh x trong của ôtômat A1 chưa được thăm bởi đỉnh {x, y} của ôtômat A.

2) Thành phần 2: Tên vị trí y và tập Ay các đỉnh kề của đỉnh y trong của ôtômat A2 chưa được thăm bởi đỉnh {x, y} của ôtômat A.

Ví dụ: Ngăn xếp S được thể hiện bằng cấu trúc mảng trong ngôn ngữ lập trình PHP như sau:

$S = array(

i => array( //thông tin đỉnh thứ i+1 trong đường đi x => array(vx1,v x2,…,v xk), //đỉnh x và các đỉnh kề với x y => array(vy1,v y2,…,v yk) //đỉnh y và các đỉnh kề với y ),

);

Các biến toàn cục được sử dụng trong thuật toán gồm có: <x, y> chỉ đỉnh cuối cùng của S, <xnext1, ynext2> chỉ đỉnh tiếp theo sẽ bổ sung vào S, Syschr lưu tập các nhãn đồng bộ của 2 ôtômat A1, A2. Hàm Adj(x, Ai) trả về tập các đỉnh kề của đỉnh x trong ôtômat Ai. Hàm getSyschr(A1, A2) trả về tập các nhãn chuyển đồng bộ. Hàm Push(<x, y>, Adj(x, A1), Adj(y, A2), S) thêm đỉnh <x, y> và tập Ax = Adj(x, A1), Ay = Adj(y, A2) vào cuối S. Hàm getSucc(x, y, xnext1, ynext2, S, Syschr) tìm và trả về đỉnh <x, y> đỉnh cuối trong S và đỉnh tiếp theo <xnext1, ynext2> thêm vào S (lưu ý: mỗi đỉnh <xnext1, ynext2> chỉ xuất hiện 1 lần trong S) đồng thời loại xnext1 khỏi tập Ax

và loại ynext2 khỏi Ay. Hàm pop(S) loại phần tử cuối ra khỏi S. Cuối cùng thuật toán trả về ôtômat hợp song song A của 2 ôtômat A1, A2. Sơ đồ các thuật toán

createOtomatParallelFrom2Otomat(A1, A2) và createOtomatParallel được cho trong

{Input: A1 = (L1, l01, 1, X1, I1, E1), A2 = (L2, l02, 2, X2, I2, E2) {Output: Ôtômat hợp song : A = (L,l0,  ,X,I,E)}

Function createOtomatParallelFrom2Otomat(A1, A2): Otomat; begin

//Khởi tạo otomat hợp song song A

L = ; l0 = {l01,l02};  = ; X = X1  X2; I = ; E = ; S = ;

Syschr = getSyschr(A1, A2);

push(<l01,l02>, Adj(l01, A1), Adj(l02, A2), S);

Thêm mới đỉnh < l01,l02> với hệ số LDI là tổng các hệ số LDI của 2 đỉnh l01,l02 và bất biến I(l01)  I(l01) vào L;

while S ≠  do begin

getSucc(l1, l2,lnext1,lnext2, S, Syschr); if lnext1 = null hoặc lnext2 = null then begin

pop(S); loop; {quay lui} end;

if I(lnext1)  I(lnext2) ≠  then begin

Bổ sung <lnext1,lnext2> với hệ số LDI là tổng các hệ số LDI của 2 đỉnh lnext1,lnext2 và bất biến I(lnext1)  I(lnext2) vào L;

end;

if {e = (<l1, l2>, , a, λ, <lnext1,lnext2>) có  ≠ } then begin

Bổ sung cung (<l1, l2>,<lnext1,lnext2>) có nhãn a, ràng buộc 

và tập các đồng hồ reset λ vào E; end;

if (<lnext1,lnext2>  S) then begin

push(<lnext1,lnext2>, Adj(lnext1, A1), Adj(lnext2, A2), S); end;

end; return A; end;

{Input: Ai = (Li, l0i, i, Xi, Ii, Ei), i = 1,2,…, n} {Output: Ôtômat hợp song : A = (L,l0,,X,I,E)} Function createOtomatParallel: Otomat; begin for i = 1 to n do begin if (i == 1) then begin A = createOtomatParallelFrom2Otomat(Ai, Ai+1); end; if (i > 1) then begin A = createOtomatParallelFrom2Otomat(A, Ai+1); end; end; return A; end;

Bảng 3.2: Thuật toán xây dựng ôtômat hợp song song tổng quát 3.1.2. Thuật toán xây dựng đồ thị vùng đạt được nguyên 3.1.2. Thuật toán xây dựng đồ thị vùng đạt được nguyên

Thuật toán xây dựng đồ thị vùng đạt được nguyên được mô tả trong bảng 4.1 ở trang 65 trong Luận án tiến sĩ Toán học của TS. Phạm Hồng Thái như sau.

{input: ôtômat thời gian A}

{output: đồ thị vùng đạt được nguyên RG =(V,E)} Function Integral-Reachability-Graph;

Begin

V = {<s0,π0>}; E = ; while (true) do begin

if mọi đỉnh trong V đã được thăm then exit; lấy v = <s,π>  V là đỉnh chưa được thăm; for với mỗi phép chuyển e = (s, φ ,a,λ,s’) do begin

for d =0 to K do begin

if (π + d)[λ := 0] |= I(s’) then loop; π’ =(π + d)[λ := 0];

if <s’,π’>  V then bổ sung <s’,π’> vào V; if (<s,π>,<s’,π’>)  E then begin

bổ sung e = (<s,π>,<s’,π’>) vào E; if π + d = πK then l(e)=u(e)=d; else begin l(e)=d; u(e)=; end; end ;

end; end;

đánh dấu <s,π> đã được thăm; end ;

End.

Bảng 3.3: Thuật toán xây dựng đồ thị vùng đạt được nguyên

3.1.3. Thuật toán xây dựng đồ thị trọng số G phục vụ kiểm chứng LDI

Ý tưởng: Tư tưởng cơ bản trong xây dựng đồ thị trọng số G là “rời rạc hóa” đồ thị đạt được nguyên RG bằng cách xây dựng mỗi cung (vi,vj,[l,u]) sẽ được thay bằng một họ các đường đi nối vi, vj sao cho độ dài (trọng số) của các đường đi lần lượt là các số nguyên l, l+1, … , u. Tức cung (vi,vj,[l,u]) được cụ thể hóa thành u-l-1 đường đi nối vi, vj thể hiện tính rời rạc hóa được của LDI. Điều này được thực hiện trên giả thiết RG không chứa cung vô hạn.

Thuật toán xây dựng đồ thị trọng số G = (V,E,) từ RG = (V1,E1) (không chứa cung vô hạn) được thực hiện theo các bước sau:

Bước 1: V = V1, E = E1.

Bước 2: Đối với mỗi cung e = (vi,vj,[lij,uij]) tập đỉnh V, cung E và hàm trọng số

: V  E  R của G được mở rộng thành: 1. V = V  { 1, 2,..., uij1 ij ij ij v v v } và (vijk ) = cvi , với k = 0,1,2,…, uij-1 (với qui ước vij0 cho vi và uij

ij

v cho vj),

3. E = E  {(vijk,vijk1)|k=0..uij-1}, và (vijk,vijk1) = 1, k = 0..uij-1, 4. E = E  {(vijk,vj)|k = lij..uij-1}, và (vijk,vj) = 0, k = lij..uij-1. Chú ý: Trường hợp lij  uij đồ thị sẽ có 2 cung từ uij1

ij

v đến vj, một cung có trọng số 1 và cung còn lại có trọng số 0 (xem hình bên dưới). Để đảm bảo G là đồ thị đơn ta sẽ “chia đôi” cung có trọng số 0 thành 2 cung bằng cách thêm đỉnh uij

ij

v và cung này

được thay bằng 2 cung ( uij1

ij

v , uij

ij

v ) và ( uij

ij

v ,vj). Thuật toán này sẽ được cụ thể hóa trong phần cài đặt, xem cài đặt này trong phần Phụ lục A.

Hình sau đây minh họa cho việc xây dựng G từ một đồ thị RG đơn giản với 2 cung.

Hình 3.1: Xây dựng đồ thị G từ đồ thị vùng đạt được nguyên RG 3.1.4. Thuật toán kiểm chứng LDI 3.1.4. Thuật toán kiểm chứng LDI

Ý tưởng thuật toán: Thuật toán được xây dựng theo kỹ thuật vét cạn để duyệt mọi đường đi với mọi đỉnh xuất phát cố định của đồ thị trọng số đạt được G. Thuật toán

được xây dựng gồm 2 hàm, hàm thứ nhất là traverse(vstart) duyệt mọi đường đi xuất phát từ một đỉnh vstart cố định, và hàm thứ 2 là Checking-LDI sẽ gọi hàm traverse(vstart) với mọi đỉnh vstart V để quyết định tính thỏa của ôtômat A đối với LDI.

Hàm traverse(vstart) được xây dựng theo kỹ thuật quay lui như sau: đường đi p xuất phát từ đỉnh ban đầu vstart của G với l(p) = 0 và (p) = 0, đi dọc theo các cạnh tới các đỉnh mới cho đến khi l(p) ≥ A. Bắt đầu từ thời điểm l(p) ≥ A trở đi, tại mỗi đỉnh mới nếu l(p) > B thì thuật toán quay lui. Ngược lại (tức B ≥ l(p) ≥ A) nếu θ(p) > M thì thuật toán dừng và cho câu trả lời G |≠ LDI và nếu θ(p) ≤ M thì thuật toán đi tiếp đến các đỉnh khác. Thuật toán quay lui khi không còn đỉnh mới để đi tiếp thì dừng lại và cho câu trả lời G |= LDI.

Trường hợp B = ∞, để tránh vòng lặp vô hạn, thủ tục sẽ xử lý các chu trình gặp được từ lúc l(p) ≥ A trở đi như sau: Nếu chu trình dương thì thuật toán dừng và kết luận G |≠ LDI. Nếu chu trình âm hoặc bằng 0 thì việc đặt chu trình này vào đường đi là không cần thiết vì giá của đường đi vẫn không tăng, do vậy thuật toán quay lui.

Để cài đặt thuật toán sử dụng một ngăn xếp p để lưu lại đường đi. Mỗi phần tử

của p gồm 2 thành phần: tên đỉnh x và tập đỉnh Ax chưa thăm bởi x. Thủ tục succ(p) sẽ trả lại đỉnh y  Ax (với x là đỉnh cuối của p) và đồng thời loại y ra khỏi Ax. Như vậy x có thể xuất hiện nhiều lần trong p, tuy nhiên tại mỗi vị trí xuất hiện các tập đỉnh Ax là hoàn toàn độc lập với nhau và đều được tạo bởi Adj(x) là tập các đỉnh kề của x.

Các biến toàn thể được sử dụng trong thuật toán gồm: v, v’ để chỉ đỉnh cuối của p và đỉnh sẽ được bổ sung ở bước tiếp theo. Biến preach dùng để lưu lại vị trí tại đó đường đi p đạt đến độ dài A (các chu trình chỉ được xử lý nếu xuất hiện sau vị trí preach). Để điều khiển việc đánh dấu này thuật toán sử dụng biến preach như một biến lôgic nhận giá trị 1 nếu l(p) ≥ A và 0 nếu ngược lại. Hàm succ(p) tìm và trả lại đỉnh tiếp theo (đồng thời loại khỏi tập chưa thăm) hoặc trả lại giá trị NULL. Các hàm l(p), θ(p), l(C), θ(C) trả lại độ dài và giá của đường đi p và chu trình C. Thủ tục pop(p) loại phần tử cuối ra khỏi p và đồng thời tính toán lại các giá trị l(p), θ(p). Thủ tục push(x, Adj(x), p) thêm đỉnh x cùng tập Ax = Adj(x) vào cuối p và đồng thời tính toán lại các giá trị l(p), θ(p). Cuối cùng thuật toán trả lại giá trị TRUE nếu LDI được thoả bởi G và

FALSE trong trường hợp ngược lại. Sơ đồ của các thuật toán traverse(vstart) và Checking-LDI được cho trong các bảng 3.4 và 3.5.

{input : G =(V,E),D}

{output : TRUE nếu và chỉ nếu G(vstart) |= D} Function Traverse(vstart): Boolean;

Begin

p = ; push(vstart,Adj(vstart),p); while p ≠  do begin

if succ(p) == NULL then begin pop(p); loop;end; {quay lui} v’ = succ(p); push(v’, Adj(v’),p);

if l(p) < A then begin reach = 0; loop;end;

if reach == 0 then begin preach = v’; reach =1; end; if l(p) > B then begin pop(p); loop;end; {quay lui} if ((p) > M) then return FALSE; {A ≤ l(p) ≤ B }

if C (đoạn từ preach đến v’) và B =  then begin if (C) > 0 then return FALSE;

if (C) ≤ 0 then pop(p); {quay lui} end ;

end;

return TRUE; End;

Bảng 3.4: Thuật toán kiểm chứng LDI với đỉnh xuất phát cố định

{input: G =(V,E), D}

{output: G |= D hoặc G |≠ D} Function Chekcking-LDI: Boolean; Begin

for với mỗi đỉnh v V do begin

if Traverse(v) == FALSE then return G |≠ LDI; end;

return G |= LDI; End ;

Bảng 3.5: Thuật toán kiểm chứng LDI tổng quát

Nhận xét: Thuật toán kiểm chứng LDI Checking-LDI có độ phức tạp cao, độ phức tạp hàm mũ trong trường hợp xấu nhất vì phải duyệt qua tất cả các chu trình của đồ thị bằng phương pháp vét cạn quay lui.

3.2. Các chi tiết kỹ thuật

Luận văn thực hiện cài đặt công cụ phần mềm kiểm chứng trên nền web sử dụng ngôn ngữ lập trình PHP, một ngôn ngữ lập trình mã nguồn mở, rất mạnh, đặc biệt là hoàn toàn miễn phí để viết mã, với hi vọng phần mềm sẽ sử dụng được sức mạnh của các web server để giải quyết bài toán kiểm chứng công thức LDI có độ phức tạp hàm mũ hiệu quả hơn. Thông tin về môi trường cài đặt như sau:

– Ngôn ngữ lập trình: PHP-5.2.8 – Web server: Apache

– Ngoài ra còn sử dụng: Html, Javascript, Template engine smarty, v.v… Để phục vụ cho việc viết mã, luận văn cũng đã xây dựng một framework đơn giản theo mô hình MVC (Model - View - Controller), MVC là một trong những mô hình thiết kế được sử dụng rất phổ biến hiện nay trong kỹ thuật phần mềm.

Cấu trúc thư mục source code được thiết kế như hình sau:

Hình 3.2: Cấu trúc thư mục source code

3.3. Đầu vào và đầu ra của bộ kiểm thử

Đầu vào (Input) của bộ kiểm chứng là một hệ thời gian thực được đặc tả bằng một hệ các ôtômat thời gian ở dạng tổng quát A=<L, l0, , X, I, E>, tức là có tập đồng hồ X = {x1,x2,…,xn} và các ràng buộc có dạng := x  c | x  c | x  c | x  c | x – y  c | x – y  c | , ở đây x, y  X và c  N. Các thuộc tính (tính chất) mong muốn của hệ thống được đặc tả bằng công thức LDI. Các đặc tả này được lưu trong các file *.txt, các file *.txt này là đầu vào của bộ kiểm thử.

Đầu ra (Output) của bộ kiểm chứng gồm:

– Hiển thị lên màn hình các bước chính của quá trình kiểm chứng và hiển thị các đồ thị tương ứng với từng bước.

– Đưa ra câu trả lời “đúng” nếu hệ ôtômat thỏa công thức LDI hoặc “sai” nếu bộ kiểm chứng chỉ ra được 1 bộ dữ liệu hệ ôtômat không thỏa công thức LDI.

Mô tả một cách chi tiết hơn, bộ kiểm chứng sẽ hoạt động theo thứ tự các bước sau:

1) Bộ kiểm chứng sẽ đọc hệ ôtômat thời gian, các hệ số của công thức LDI từ file *.txt và chuyển đổi thành dữ liệu có cấu trúc lưu vào các biến trong chương trình.

2) Chương trình sẽ tự động nhận biết nếu hệ có nhiều hơn 1 ôtômat thì sẽ thực hiện tạo ra 1 ôtômat hợp song song của các ôtômat thành phần, còn nếu hệ chỉ có 1 ôtômat thì sẽ không làm gì mà giữ nguyên.

3) Chuyển ôtômat hoặc ôtômat hợp song song (trường hợp hệ thống có nhiều

hơn 1 ôtômat) thành đồ thị vùng đạt được nguyên dựa trên kĩ thuật ε- nguyên hóa được trình bày tại chương 4 trong Luận án Tiến sĩ Toán học của TS.

Phạm Hồng Thái.

4) Chuyển đồ thị vùng đạt được nguyên sang đồ thị trọng số phục vụ kiểm chứng LDI bằng kĩ thuật rời rạc hóa.

5) Duyệt đồ thị trọng số LDI, tính toán và đưa ra kết luận ôtômat thỏa công thức LDI hay không, tức là hệ thống được đặc tả có thỏa mãn các tính chất của hệ thống được đặc tả hay không. Trường hợp không thỏa thì phải chỉ ra được nơi xảy ra lỗi trong hệ thống.

6) Vẽ đồ họa và hiển thị lên màn hình các đồ thị ôtômat, đồ thị vùng đạt được nguyên và đồ thị trọng số LDI.

3.4. Cấu trúc dữ liệu

Sử dụng ngôn ngữ lập trình PHP để mô tả các cấu trúc dữ liệu lưu trữ các ôtômat, đồ thị vùng đạt được nguyên, đồ thị trọng số phục vụ kiểm chứng LDI và các cấu trúc dữ liệu khác để sử dụng trong chương trình.

3.4.1. File dữ liệu đầu vào

Dữ liệu đầu vào được cho dưới dạng ôtômat thời gian, các hệ số của vị trí của ôtômat và các hệ số A, B, M của công thức LDI được lưu trong 1 file *.txt. Chương trình sẽ đọc dữ liệu từ file *.txt và tính toán để được kết quả: ôtômat, ôtômat hợp song song đạt được, đồ thị vùng đạt được nguyên, đồ thị trọng số phục vụ LDI, kết quả kiểm chứng, thời gian chạy chương trình.

File dữ liệu đầu vào *.txt được thiết kế như sau:

(nếu giá trị nào đó là vô cùng thì thay bằng chữ U)

Dòng 1: {Hệ số A}_{Hệ số B}_{Hệ số M} // hệ số của công thức LDI

Dòng 2: {số đỉnh}_{tên vị trí ban đầu} // ôtômat 1

Dòng 3: {tên vị trí}#xi_low_up|xj_low_up|…#{hệ số ldi} // ôtômat 1

({tên vị trí}#{các ràng buộc}#{hệ số ldi}) //mỗi đỉnh 1 dòng

Dòng i: {số cạnh} // ôtômat 1

Dòng i+1: li#xi_xj_low_up|…#{nhãn}#xi_1|xj_1|…#lj // ôtômat 1

(phép chuyển e = < li, (low <= xi - xj <=up,…), {nhãn},{ xi, xj,…}, lj >)

….

(nếu có ôtômat 2,3,… thì lặp lại từ dòng 2 và lưu vào các dòng tiếp theo)

Ví dụ 3.1: Một hệ thống được đặc tả bằng ôtômat thời gian:

Hình 3.3: Ôtômat thời gian

Tính chất mong muốn được đặc tả bằng công thức LDI: 0  l s1 - s2  5 Khi đó file otomat1.txt có nội dung như sau:

0_U_5 2_s1 s1#x2_0_5#1 s2#x1_0_8|x2_0_10#-1 2 s1#x2_x0_3_U#a#x2_1#s2 s2#x1_x0_6_U|x2_x0_4_U#b#x1_1#s1

3.4.2. Ôtômat

Một phần của tài liệu (LUẬN văn THẠC sĩ) phân tích, thiết kế và cài đặt kiểm chứng một hệ thời gian thực (Trang 26)