SAT là bài toán quan trọng được ứng dụng trong nhiều lĩnh vực của công nghệ thông tin nói chung và công nghệ phần mềm nói riêng. Dưới đây trình bày
thủ tục DPLL (Davis Putnam Logemann Loveland năm 1962) mô tả các bước giải bài toán SAT.
Thủ tục DPLL [26] được sử dụng để tìm một phép gán thỏa mãn cho công thức F có dạng CNF. Phép gán được xác định dần từng bước một. Phép gán thành phần ở bước tiếp theo được xác định dựa trên phép gán thành phần ở bước hiện tại. Nếu việc tìm kiếm thất bại hoặc gặp phải trường hợp xung đột thì áp dụng luật backtrack (quay lui) ngay tại vị trí tìm kiếm thất bại.
Thuật toán DPLL là thuật toán khá phổ biến và được sử dụng trong hầu hết các máy giải SAT. Mục đích chính của nó là tìm ra một phép gán M thỏa mãn công thức F tồn tại ở dạng CNF. Trong đó:
Một literal l là được định nghĩa trong M nếu l nhận giá trị đúng hoặc sai trong M. Ngược lại, l không được định nghĩa trong M.
Một mệnh đề là đúng trong M nếu tồn tại một literal thuộc mệnh đề nhận giá trị đúng trong M.
Một công thức F là đúng trong M hoặc SAT trong M nếu tất cả các mệnh đề trong của F đều nhận giá trị đúng trong M. Khi đó ta nói M là mô hình của F ký kiệu là M ⊨ 𝐹.
Về cơ bản, DPLL chính là thuật toán tìm kiếm theo chiều sâu. Với những cải tiến nhất định để khắc phục vấn đề về không gian trạng thái.
Thủ tục DPLL thực hiện với đầu vào là một biểu thức F có định dạng CNF và thực hiện tính toán một chuỗi hữu hạn các trạng thái là các phép gán thỏa mãn cho các mệnh đề con của F như ║F ⟹ ⋯ ⟹ 𝑆. Trạng thái khởi tạo là trạng thái rỗng kí hiệu () và kết thúc khi gặp trạng S. Trạng thái này nhận giá trị false nếu F là không thỏa mãn (UNSAT), hoặc trả về một phép gán M thỏa mãn F’ (M ║ F’), trong đó M là mô hình của F (𝑀 ⊨ 𝐹) khi F thỏa mãn. Trong trường hợp này F’ là trạng thái cuối cùng và là biểu thức dạng CNF đã được biến đổi từ F bằng cách thêm vào một số các mệnh đề trong suốt quá trình thực hiện thủ tục DPLL. Nó khác với công thức F ở đầu vào.
Hình 3.1.a Hình vẽ mô tả thủ tục DPLL
Cơ chế hoạt động của DPLL được thể hiện trong hình 3.1.
Hình 3.1.b. Sơ đồ cơ chế hoạt động của thủ tục DPLL cho SAT [6]
Algorithm : DPLL-SAT
Input: Một công thức lô gíc mệnh đề B
Output: “Satisfiable” nếu công thức là thỏa mãn và “Unsatisfiable” trong trường hợp
ngược lại.
1. function DPLL
2. if BCP() = “conflict” then return “Unsatisfiable”;
3. while (true) do
4. if ¬Decide() then return “Satisfiable”;
5. else
6. while (BCP() = “conflict”) do
7. backtrack-level := Analyze-Conflict();
8. if backtrack-level < 0 then return “Unsatisfiable”;
9. else BackTrack(backtrack-level);
Decide (Luật quyết định)
BCP
(Luật unit Propagete)
SAT Analyze Conflict (bộ phần tích xung đột) UNSAT Conflict (xung đột) Backtrack
Trong đó, dl là biến kiểm tra để quyết định có quay lui không.
Thủ tục DPLL áp dụng luật unit propagate để suy luận phép gán tiếp theo từ phép gán M hiện tại và công thức CNF hiện tại F. Luật decide được áp dụng khi không thể xác định được giá trị của một literal trong công thức F thông qua luật unit propagate. Luật Fail và luật backtrack được áp dụng khi xảy ra trường hợp không thỏa mãn khi một hoặc nhiều mệnh đề của công thức CNF F nhận giá trị sai trong phép gán hiện tại M. Nếu công thức dạng CNF F là UNSAT luật fail được áp dụng khi toàn bộ các literal trong công thức F đều được xác định. Ngược lại thì ta áp dụng luật backtrack.
Dưới đây là các luật cơ bản của DPLL [25]:
Luật Unit Propagate:
M ║F, C ˅ l ⟹ M l ║F ,C ˅ l Nếu M ⊨ C l được định nghĩa trong M. Luật Decide: M ║F ⟹ M ld ║ F Nếu
l hoặc l xuất hiện trong một mệnh đề của F
l chưa được định nghĩa trong M.
Luật Fail:
M ║F, C ⟹ FailState Nếu
M ⊨ C và
M không còn chứa literal quyết định nào.
Luật Backtrack:
M ld N ║ F,C ⟹ Ml║ F,C Nếu
M ld N ⊨ C
N không chứa literal quyết định
Ví dụ ứng dụng DPLL
Cho công thức F = (¬1 ˅ 2) (¬3˅ 4) ( ¬5˅¬6) (6˅¬5˅¬2). Áp dụng thuật toán DPLL để tìm một mô hình M thỏa mãn biểu thức F.
1d ║(¬1 ˅ 2), (¬3˅ 4),( ¬5˅¬6),(6˅¬5˅¬2) ⟹ (Luật unit propagate). 1d 2║(¬1 ˅ 2), (¬3˅ 4),( ¬5˅¬6),(6˅¬5˅¬2) ⟹ (Luật decide).
1d 2 3d║(¬1 ˅ 2), (¬3˅ 4),( ¬5˅¬6),(6˅¬5˅¬2) ⟹ (Luật unit propagate). 1d 2 3d 4║(¬1 ˅ 2), (¬3˅ 4),( ¬5˅¬6),(6˅¬5˅¬2) ⟹ (Luật decide).
1d 2 3d 4 5d║(¬1 ˅2), (¬3˅ 4),( ¬5˅¬6),(6˅¬5˅¬2) ⟹ (Luật unit propagate). 1d 2 3d 4 5d¬6║(¬1 ˅ 2), (¬3˅ 4),( ¬5˅¬6),(6˅¬5˅¬2) ⟹ (Luật backtrack)
Vì phép gán 1d 2 3d 4 5d¬6 làm cho mệnh đề (6˅¬5˅¬2) false. Mệnh đề (6˅¬5˅¬2) là không thỏa mãn nên thực hiện quay lui.
1d 2 3d 4 ¬5d║(¬1 ˅ 2), (¬3˅ 4),( ¬5˅¬6),(6˅¬5˅¬2).
Sau bước này, tất cả các mệnh đề trong F là true nên thuật toán dừng lại trả về phép gán M (1 = đúng, 2 = đúng, 3 = đúng, 4 = đúng, 5 = sai, 6 tùy ý).
Ngoài 4 luật cơ bản kể trên, thuật toán DPLL với việc học mệnh đề (clause learning) còn bổ sung thêm hai luật mới luật learn và luật forget.
Luật Learn
𝑀 ║ F ⟹𝑀 ║ F C nếu
F ⊨ C và Tất cả các atom của C đều xuất hiện trong F
Luật Forget
𝑀 ║ 𝐹 𝐶 ⟹𝑀 ║ F nếu 𝐹 ⊨ 𝐶
Trong hai luật này mệnh đề C được gọi là luật learn và luật forget tương ứng. Trong luật Backtrack mệnh đề C 𝑙′ là mệnh đề xung đột (conflict). Thì mệnh đề xung đột được học bằng luật learn để tránh xảy ra trường hợp xung đột tương tự. Luật forget được áp dụng để giải phóng bộ nhớ bằng cách loại bỏ mệnh đề C trong trường hợp nhiều lần mệnh đề C là nguyên nhân xảy ra xung đột.
Ví dụ 2: Ví dụ này áp dụng luật backtrack và luật learn để tìm một mô
hình đầu vào của công thức dạng F =(l1 l2) (l3 l2 l4) (l3l4). ║(l1 l2) (l3 l2 l4) (l3l4) ⟹ (luật decide)
l1
d║(l1 l2) (l3 l2 l4) (l3l4) ⟹ (luật unit propagate) l1
d
l1d l2 l3d║(l1 l2) (l3 l2 l4) (l3l4) ⟹ (luật unit propagate) l1 d l2 l3 d l4║(l1 l2) (l3 l2 l4) (l3l4) ⟹ (luật backtrack) l1 d l2║(l1 l2) (l3l2 l4) (l3 l4) ⟹ (luật learn)
l1d l2║(l1 l2) (l3l2 l4) (l3 l4) ⟹ (luật unit propagate) l1d l2l3║(l1 l2) (l3l2 l4) (l3 l4). Đây là trạng thái cuối cùng. Một phép gán thỏa mãn đã được chỉ ra. M (l1 = đúng, l2 = đúng, l3 = sai).