thức chuẩn tắc hội của các sự kiện (facts) tương ứng với lý thuyết ghép nối (plug-in) dựa trên việc phân loại (của DPLL) các thuật ngữ được sử dụng trong các nguyên tử (literal). Các lý thuyết ghép nối được lấy ra từ những sự kiện mới trong miền của DPLL, từ các sự kiện được xác định và chuyển nó tương ứng vào lõi như các tiên đề mới. Bất kỳ sự tương đương giữa các điều khoản trong các tiên đề mới được đưa ra và các thuật ngữ tồn tại được dị tìm bởi mơ đun congruence closure engine, và các biểu thức tương ứng được đưa ra. Nếu các biểu thức đưa ra và các quan hệ được chia sẻ các biến (bởi lý thuyết ghép nối) thì mơ đun lõi xác định chúng với tất cả các ghép nối. Lõi của mơ đun sẽ dị tìm nếu cơng thức đầu vào và các sự kiện đưa ra là không thỏa mãn với lệnh gán hiện tại, khi đó nó sẽ quay lui. Thủ tục này lặp lại cho đến khi lệnh gán thỏa mãn hoặc định dạng đầu vào được coi là khơng thỏa mãn.
Ví dụ 5.1: ví dụ có các ràng buộc chuỗi như Bảng 5.1. Thành phần mô đun lõi trong bộ giải Z3–str khơng thể giải thích các hoạt động chuỗi; thay vào đó nó xử lý chúng như bốn biến logic độc lập (e1, e2, e3 và e4) và cố gắng chỉ định
giá trị logic cho chúng. Trong Bảng 5.2 giải thích q trình các tốn tử chuỗi qua các thành phần lõi của Z3–str và sự tương tác với bộ giải lý thuyết chuỗi.
Trong Bảng 5.2, ban đầu khơng có sự kiện nào. Mô đun lõi bắt đầu bằng cách thiết lập e3 và e4 là true và đạt đến bước ba. Không mất tính tổng quát, giả sử thành phần lõi đầu tiên cố gắng gán e1 là true. Mơ đun lõi có thể tìm
các thuật ngữ chức năng tương đương, dựa trên lý thuyết về hàm tượng trưng (uninterpreted functions or function symbol). Do đó, đặt {x, y,“abc00.m,“ef g00.n}
vào một lớp tương đương và thơng báo cho trình ghép nối lý thuyết chuỗi. Trong trình ghép nối lý thuyết chuỗi Z3–str chỉ có thể biết về các thuật ngữ tương đương trong bộ lý thuyết của nó. Nếu chúng ta có phương trình length(x) = 4
thì Z3–str khơng nhận ra thực tế chiều dài của x là 4. Tuy nhiên, nếu e2 được đặt là true, Z3–str sẽ nhận ra rằng x là một hằng chuỗi có độ dài là 4. Do đó,
có thể suy luận ra length(x) = 4 và chuyển thông tin này đến lý thuyết số học.
Bảng 5.1: Ví dụ giải các tốn tử chuỗi assert(e1∨e2)∧e3∧e4)
e1 :x=concat(“abc00, m);e2 :x= “ef gh00
e3 :y=concat(“ef g00, n);e4 :x=y
Bảng 5.2: Cách Z3–str thực hiện xử lý các ràng buộc chuỗi trong Bảng 5.1
Các ràng buộc Sự kiện Lớp tương đương Hoạt động của mô đun lõi
1 y=concat(“efg”,n) y=“efg”.n {y,“efg”.n}
2 x=y x=y {x,y}{y,“efg”.n}
3 x=concat(“abc”,m) x=“abc”.m {x,“abc”.m,y,“efg”.n}
Xung đột bị xóa
Quay lui và loại bỏ sự kiện Chọn một lựa chọn khác choe1 4 x=“efgh” x=“efgh” {x,“efgh”,y,“efg”.n} “efgh”=“efg”.n n=“h”
Giải pháp SAT: x=“efgh”, y= “efgh”, n=“h”
Với ví dụ trên, trong các lớp tương đương tại bước ba thì Z3–str phát hiện xung đột và sau đó thơng báo cho các thành phần lõi về việc tìm kiếm mới thơng qua tiên đề e3∧e4 → ¬e1. Trong tiên đề mới, các thành phần cốt lõi xử lý quay lui và cố gắng gán f alse cho e1. Trong khi thực hiện quay lui, nó sẽ loại bỏ các sự kiện xung đột và thêm các lựa chọn vào các lớp tương đương. Sau đó, mơ đun lõi sẽ đưa ra e2 là true và thực hiện việc gắn ở bước bốn. Dựa trên ý nghĩa của phép nối , Z3–str suy luận rằng n phải là “h”. Việc phát hiện mới này được
cơng thức hóa bằng việc giới thiệu các biến logic mới e5 biểu diễn n = “h00 và tiên đề “ef gh00 = “ef g00.n ⇒e5, tiên đề này được gửi lại mô đun lõi. Từ các tiên đề mới, thành phần mô đun lõi đưa ra e5 là true. Sau khi tất cả các biểu thức
logic được gán và Z3–str có thể tìm thấy các giá trị thỏa mãn cho các biến x, y
và n, thủ tục tìm kiếm kết thúc.
5.3.3.2 Ngữ pháp của ràng buộc và đầu vào của bộ giải Z3–str
Ngữ pháp ràng buộc của bộ giải Z3–str trong Bảng 5.3. Kế thừa từ bộ giải này, phương pháp chỉ liệt kê ba kiểu dữ liệu nguyên thủy: int, bool, string. Trong Z3–str, trình ghép nối hỗ trợ các tốn tử chuỗi sau: phương trình chuỗi (string equation), phép nối (concatenation), độ dài chuỗi (length), substring, contains, indexOf, replace và split [114]. Luận án bổ sung quy tắc giảm cho toán tử chuỗi search, replaceAll (phần bơi màu xám chính là phần thêm vào so với Z3–str trong Bảng 5.3); và đề xuất quá trình tiền xử lý cho các toán tử như charAt, lastindexOf, trim, startsWith và endsWith.
Sau đây là mô tả ngắn gọn định dạng đầu vào của bộ giải Z3–str. Bộ giải này có thể xử lý với đầu vào là hợp của các công thức logic nguyên tử, được chuyển thành hợp của các biểu thức. Ví dụ sau minh họa với đầu vào của bộ giải chuỗi cho Z3–str, xem xét các ràng buộc chuỗi sau:
c1, c2, x:String; vi1 :Integer ; c1 =c1.concat(“te00); c2 = “aaaa_ef g_bbbb_ef g00;
x=c1.concat(c2); vi1 = x.indexOf(“ef g00); vi1≥4;
Giả sử có năm ràng buộc chuỗi trên là các biểu thức logic độc lập là (e1,e2,e3,e4 và e5) và gán giá trị cho chúng.
e1 :c1 = c1.concat(“te00); e2 :c2 = “aaaa_ef g_bbbb_ef g00;
e3 :x=c1.concat(c2); e4 :vi1 =x.indexOf(“ef g00); e5 :vi1≥4 ;
Xét các ràng buộc chuỗi trên, định dạng đầu vào của Z3–str được chuyển đổi như sau: assert (e1∧e2∧e3∧e4∧e5). Mỗi toán tử trên được chuyển đổi thành:
(assert (concat c1 “te”)); (assert (= c2 “aaaa_efg_bbbb_efg”));
(assert (= x (concat c1 c2)); (assert (=vi1 (indexOf x “efg”))); (assert (≥vi1 4)); Với giá trị đầu vào tương ứng thỏa mãn thì đầu ra của Z3–str là SAT và một mơ hình các giá trị của các biến, các giá trị dữ liệu kiểm thử thỏa mãn được chọn bất kỳ từ mơ hình này. Để dữ liệu kiểm thử đạt được độ bao phủ biên thì các ràng buộc được chọn thêm chính là phương trình tại vùng biên của các ràng
Bảng 5.3:Ngữ pháp của các ràng buộc trong Z3–str, mở rộng chosearchvàreplaceAll so với [114] Assertion ::= assert(Expr:bool) Term:bool ::=(Var:bool) | true | false | contains((Term:string), (Term:string)) Term:int ::= (Var:int) | Number | (Term:int) {+, - , x , ÷ } (Term:int) | length(Term:string)
| indexOf((Term:string), (Term:string)) |search((Term:string), (Term:string)) Term:string ::= (Var:string)
| ConstString
| concat((Term:string), (Term:string))
| substring ((Term:string),(Term:int),(Term:int)) | replace((Term:string), (Term:string), (Term:string))
|replaceAll((Term:string), (Term:string), (Term:string)) Expr:bool ::= (Term:bool) | (Term:bool) = (Term:bool) | (Term:int) {<,≤,=,≥, >} (Term:int) | (Term:string) = (Term:string) |¬(Expr: bool) | (Expr:bool) { ∧,∨,→} (Expr:bool)
buộc. Có rất nhiều lỗi trong các hệ thống được xác định tại biên giữa các hành vi hay các chức năng. Trong cách tiếp cận của luận án, các ràng buộc được thêm vào tại các điểm là ranh giới tại biên của các vị từ, được chuyển là đầu vào của Z3–str (trong ví dụ trên, ngồi các ràng buộc là đầu vào thì thêm ràng buộc thỏa mãn bao phủ biên là vi1 == 4). Do đó, dữ liệu kiểm thử được sinh ra và
thỏa mãn độ bao phủ biên.
5.3.3.3 Cải tiến thuật toán trong bộ giải Z3–str
Trong phần này sẽ giải thích các tốn tử chuỗi được hỗ trợ bởi Z3–str [114] và phần cải tiến trong thuật toán xử lý chuỗi mà luận án đề xuất. Đầu tiên đề cập đến ba toán tử nguyên thủy: phương trình chuỗi, phép nối chuỗi và độ dài chuỗi. Trong Z3–str sẽ sử dụng thuật toán giảm để giảm các tốn tử chuỗi khác thành các cơng thức tương đương dựa trên tốn tử ngun thủy. Z3 có thể
mơ hình hóa trực tiếp quan hệ tương đương giữa các đối tượng như các biến, các hằng và đặt chúng trong cùng một lớp tương đương. Do đó, chiến lược tổng quan là giảm các tốn tử chuỗi khác nhau để đơn giản hóa các quan hệ tương đương. Thuật toán Z3–str được hỗ trợ thêm, được điều khiển bởi thủ tục quay lui của mô đun lõi Z3.
a) Các toán tử chuỗi hỗ trợ của Z3–str: miêu tả các toán tử chuỗi nguyên thủy của Z3–str, thuật toán, các quy tắc giảm trong xử lý chuỗi [114].
Phép nối chuỗi: là toán tử được sử dụng phổ biến và cũng là toán tử nguyên thủy của Z3–str. Bộ ghép nối được thông báo bởi mơ đun lõi của Z3 khi tốn tử chuỗi được khẳng định (assert) như một phần của thủ tục quay lui. Cụ thể, mô đun lõi gọi hàm gọi lại (call back) trong mô đun ghép nối, cung cấp cây cú pháp trừu tượng (Abstract Syntax Tree–AST) của phương trình như một tham số. Hàm gọi lại kiểm tra AST, nếu bao gồm phép nối chuỗi thì hàm thực hiện chuyển đổi AST để giảm AST thành một cây mới mà đơn giản và dễ dàng hơn để giải. Việc giảm được chuyển đến mô đun lõi bằng cách thêm một tiên đề với các định dạng “AST → AST´’’ với AST và AST’ là cây gốc và cây ngữ pháp chuyển đổi tương ứng. Kể từ khi mô đun lõi khơng hiểu miền chuỗi thì xử lý cả AST và AST’ như các biến logic độc lập. Vì AST được gán giá trị true, với tiên
đề mới, mô đun lõi sẽ được gán giá trị true cho AST’, đây là một sự kiện kích hoạt q trình xử lý trong mơ đun ghép nối. Q trình giảm tiếp tục cho đến khi đạt được định dạng tương đương đơn giản của biểu thức; Ví dụ x=Y, với Y là một hằng chuỗi hoặc chuỗi phức hợp gồm các hằng số và các biến. Sự phụ thuộc của những biểu thức đơn giản này sau đó được xây dựng để mơ đun ghép nối có thể gán các giá trị cho các biến tự do (tức là các biến số khơng phụ thuộc vào các biến khác), nếu có thì để tạo ra một giải pháp thỏa mãn. Quá trình giảm phép nối được miêu tả trừu tượng trong Tht tốn 5.2, mơ đun lõi thực hiện việc gán true cho một biểu thức chuỗi của hai chuỗi phức hợp (ví dụ phép nối của các hằng và các biến được xác định trong Bảng 5.4). Ý tưởng chính của việc giảm sự liên kết được đưa ra trong thuật tốn này là đưa ra phương trình mới giữa các chuỗi con của hai vế của phương trình. Tổng quát hơn là đưa ra tất cả các thuật ngữ tương đương với những chuỗi con này (sử dụng mơ đun lõi của Z3 để duy trì các lớp tương đương của các thuật ngữ). Ví dụ: giả sử rằng biến chuỗi xcó lớp tương đương {x,“a00·x1}. Nếu phương trình mới x= “ab00 thì được
Thuật tốn 5.2 Thuật toán giảm của phép nối [114] CALLBACK(Y1 =Y2) 1: REDUCE (Y1 =Y2) 2: for an object Y ∈Y1|Y0 2s equivalence class do 3: REDUCE (Y1 =Y); 4: REDUCE (Y2 =Y); 5: end for
6: if (Y1 =Y2 is of the form x=s) then
7: for any Y involving x in existing eq-classesdo
8: REDUCE (Y)
9: end for
10: end if
Bảng 5.4: Định nghĩa cho Thuật toán 5.2 [114]ĐỊNH NGHĨA ĐỊNH NGHĨA
Y ∈CompoundString::= s·CompoundString|x·CompoundString|ε
x∈V ar :String s∈ConstString
split::=CompoundString →P(CompoundString×CompoundString×Expr:bool) CÁC HÀM BỔ TRỢ
split(Y) =recSplit(nil, Y)
recSplit(YL, s·YR) = ∪∀sh·st=s{<YL·sh, st·YR, true>} ∪recSplit(YL·s, YR)
recSplit(YL, x·YR) ={(YL·x1, x2·YR, x1·x2 =x)} ∪recSplit(YL·x, YR)
recSplit(YL, nil) =φ
len(s·Y) = “|s|+00·len(Y) len(x·Y) = “length(x) +00·len(Y) len(nil) = “000
xác định gửi tới mô đun ghép nối. Chúng được áp dụng thuật toán giảm phép nối để đưa ra x1 = “b00 từ sự kiện mới này và lớp tương đương. Hơn nữa, nếu phương trình mới có định dạngx=s với s là hằng chuỗi, trong dịng6−8chỉ ra trong Thuật tốn 5.2 đi qua tất cả các biểu thức trong các lớp tương đương bao gồm x và thay thế x là s, có thể làm giảm hơn nữa. Độ phức tạp của Thuật 5.2
phụ thuộc vào hai vòng lặp for (dòng2đến dòng 5 và từ dòng7đến dòng 9), giả
sử số đối tượng trong lớp tương đương Y1 và Y2 là m và số đối tượng x thuộc lớp tương đương Y làn. Do đó, độ phức tạp của Thuật tốn là max(O(m), O(n)). Vì m và n đều là các số hữu hạn. Như vậy, sau một số hữu hạn bước thì thuật tốn sẽ dừng.
Các quy tắc giảm của Z3–str: Có các quy tắc giảm đầu tiên trong Bảng 5.5 là giảm phép nối với các định nghĩa liên quan trong Bảng 5.4. Trong Bảng 5.5, cột thứ hai chỉ ra sự chuyển đổi và cột thứ ba chỉ ra điều kiện của việc giảm. Chú ý rằng, quy tắc chuyển đổi là “cong_thuc_goc → cong_thuc_moi00,
với các tiên đề cần thiết mà được thêm vào mô đun lõi của Z3. Để biểu diễn dễ dàng hơn, Z3–Str làm phẳng một AST thành một chuỗi phức hợp là một phép nối phẳng của các hằng và các biến. Chú ý trong khi làm phẳng, tất cả các chuỗi hằng được nối với một chuỗi hằng dài hơn.
Quy tắc (HEAD-CONST-RMV) loại bỏ hằng chuỗi con bên trái chung nhất ở phía vế bên trái (LHS) và vế bên phải (RHS) của một phương trình. Giả sử rằng RHS có hằng chuỗi dài hơn mà khơng mất tính tổng qt. Nếu LHS và RHS khơng có tiền tố chung thì một tiên đề “¬cong_thuc_goc00 được thêm vào, gây ra sự quay lui. Quy định (TAIL-CONST-RMV) cũng tương tự.
Sau khi áp dụng các quy tắc loại bỏ hằng, chúng ta nhận được một điểm mà một trong hai LHS hoặc RHS bắt đầu với một biến. Quy tắc (SPLIT) cho phép giảm thêm cho các biểu thức như vậy. Giả sử LHS có dạng là x1·Y1, trong đó
x1 là một biến và Y1 là một chuỗi phức hợp. Quy tắc phân chia RHS chuỗi phức hợp Y2 thành hai chuỗi con Yh và Yt, bằng cách gọi hàm split(), và khẳng định x1 = Yh và Y1 = Yt. Hàm split có thể cũng tạo ra một ràng buộc mới C biểu thị hiệu ứng của việc chia tách. Chú ý rằng có nhiều cách chia Y2. Vì thế, hàm
split() trả về một tập các chia tách, được liên kết bởi toán tử Y. Toán tử này tương tự như giá trị logic hoặc nó yêu cầu chỉ một lựa chọn có thể true.
Ví dụ,xYy=truengầm ý rằng hoặcx=true, y=f alsehoặc x=f alse,y =true.
Các miêu tả của hàm split(Y) được chỉ ra trong Bảng 5.4. Đó là một q trình lặp đệ quy theo hàm recSplit(YL, YR), trong đó trả về một tâp các chia tách có
thể xảy ra. Cụ thể, nó chia tách các phần tử đầu củaYR tại một thời điểm và di chuyển nó đến cuối cùng củaYL. Do đó, q trình bắt đầu với YL =nil∧YR =Y
và kết thúc với YL =Y ∧YR = nil. Nếu nguyên tử là một hằng số s, nó tạo ra
nhiều cách chia tách và việc chia tại các vị trí khác nhau trongs. Nếu nguyên tử
là biến x, nó tạo ra một cách chia, đó là chia xthànhx1 và x2 với x1 và x2 là các biến tự do. Sự tương quan của các biến được xác định trong điều kiện chia tách sẽ là một phần trong việc giảm của phương trình mới (tức là C trong Quy tắc (SPLIT)). Ví dụ: Xem xét một chuỗi phức hợp “ab00·x. Các chia tách được tạo
ra: { (“00,“ab00·x, true), (“a00,“b00·x, true), (“ab00, x, true), (“ab00·x1, x2, x1·x2 =x)}.
Một nhận xét quan trọng của quy tắc tách là các tùy chọn riêng biệt (của toán tử Y) trong công thức chuyển đổi đơn giản hơn so với công thức gốc. Điều này đảm bảo trong việc giảm công thức gốc. Chú ý rằng những lựa chọn đơn giản này sẽ khai thác và tiếp tục giảm của Z3–str một cách riêng biệt. Tuy nhiên,
Bảng 5.5: Các quy tắc giảm [114]
Tên quy tắc Quy tắc giảm Điều kiện
Head-Const- Rmv s1·x1·Y1 =s2·Y2 → x1·Y1 =s3·Y2 s1·x1·Y1 =s2·Y2 → ¬(s1·x1·Y1 =s2·Y2) if s1 ·s3 =s2 if s1 is not a prefix of s2 Tail-Const- Rmw Y1·x1·s1 =Y2·s2 → Y1·x1 =Y2·s3 Y1·x1·s1 =Y2·s2 → ¬(Y1·x1·s1 =Y2·s2) if s3 ·s1 =s2 if s1 is not a suffix of s2 Split x1 ·Y1 = Y2 → Y(Yh,Yt,C)∈split(Y2)(x1 = Yh)∧ (Y1 =Yt)∧C Concretize (x=s)∧(Y1·x·Y2) → Y1·s·Y2 if x=s Stringlen Y1 =Y2 → len(Y1) =len(Y2)
Free-Var Context → x= “00Yx= “@00Yx= “@@00... x a free variable
chúng cũng thêm ràng buộc mới C cho hệ thống trong suốt q trình tách, nó có thể tăng tính kết thúc của việc chia tách.
Quy tắc (Concretize) thay thế biến x trong Y1 ·x·Y2 với a là hằng chuỗi khi chúng trở thành tương đương. Chú ý rằng để đảm bảo công thức chèn vào là một tiên đề, chúng ta có liên kết x=s với biểu thức ban đầu.
Phương trình chuỗi: Khi việc giảm không thể thực hiện được nữa, nếu mỗi lớp tương đương là một hằng số, quá trình giải kết thúc với một giải pháp SAT.