# 第五章 Constraint Satisfaction Problem ## 約束滿足問題(CSP) - 目標是尋找滿足所有約束的解 - 組成要素 - 變數:有限數量的 $V_1$, $V_2$, ..., $V_n$ - 值域:變數可以取的值的非空集合 $D_{V_1}$, $D_{V_2}$, ..., $D_{V_n}$ - 約束:有限數量的約束條件 $C_1$, $C_2$, ..., $C_m$ - 限制變數之間關係的條件 - 例如:$C_1$ 為 $V_1 \neq V_2$ - 狀態是對部分或全部變數賦值的一種分配(assignment) - 解答必須具有完整性(complete)和一致性(consistent) - 完整性:所有變數皆已賦值 - 一致性:滿足所有約束條件 - 應用案例 - 數獨 - 圖著色問題 - 密碼分析 - 排程問題 #### 範例:Map Coloring ![image](https://hackmd.io/_uploads/HJ4XMOqAJl.png) - 變數:$WA$, $NT$, $SA$, $Q$, $NSW$, $V$, $T$ - 值域:$D_i = \{red, green, blue\}$ - 約束:相鄰的區域不能有相同顏色 - $WA \neq NT$... - $(WA, NT) \in \set{(red, green), (red, blue), (green, blue), \dots}$ - Solution:$WA = red$, $NT = green$, $SA = blue$, $Q = red$, $NSW = green$, $V = blue$, $T = green$ ### 約束圖(Constraint Graph) Constraint Graph 可以用來表示 CSP 的結構 - 節點為變數,邊為約束 - 例如: - $WA$ 和 $NT$ 之間有一條邊,表示它們之間有約束 - $T$ 不和其他變數連通,可以被視為獨立的子問題 ```graphviz digraph map_coloring_graph { rankdir=LR; edge[dir=none]; WA -> NT WA -> SA NT -> SA NT -> Q SA -> Q SA -> NSW SA -> V Q -> NSW V -> NSW T->NSW[style=invis] } ``` ### CSP 的變數 - 離散變數(Discrete Variables) - 有限的值域(Finite Domains): - 對於 $n$ 個變數都各別有大小為 $d$ 的值域 - 共有 $O(d^n)$ 種完整 assignment - 例如:真質表、地圖著色問題 - 無限的值域(Infinite Domains): - 如整數、字串等 - 通常需使用「約束語言」表示條件(例如線性不等式) - 線性約束可解,非線性通常不可解(undecidable) - 例如:工作排程問題 - 連續變數(Continuous variables) - 變數可取任意實數 - 多數線性約束可用線性規劃(Linear Programming) 在多項式時間內求解 - 例如:哈伯太空望遠鏡的觀測時間安排 ### 約束的種類 - 一元約束(Unary Constraints): - 只涉及一個變數的約束 - 例如:$SA \neq green$ - 二元約束(Binary Constraints): - 只涉及兩個變數的約束 - 例如:$WA \neq NT$ - 多元約束(Global Constraints): - 涉及三個或以上變數的約束 - 例如:密碼算術中的欄位限制 - 偏好約束(Soft Constraints): - 不是硬性規定,而是「比較好」 - 例如:「紅色比綠色好」⇒ 每種指派有對應的「代價」,希望總成本最小 ### CSP 的解法 CSP 可以視為一個標準的搜尋問題(Standard Search Problem),可以用以下的方式來表示 - 初始狀態:空的指派(empty assignment):$\set{}$ - `Successor` 函數:指派合法值給未賦值的變數,並且跟約束條件沒有衝突 - Goal 測試: 所有變數都已被賦值,且滿足所有約束(complete & consistent) - Path cost:一般為每步固定成本(通常不特別考慮) - 複雜度: - Solution 的深度為變數的數量 $n$ - 分支因子$b$ 初期為 $nd$ - 在深度為 $l$ 時, $b = (n - l)d$ - 有 $n!d^n$ 個葉節點 - CSP 具有可交換性(commutativity) - 指派變數的順序**不影響結果** - 例如:先做 $WA$ 再做 $NT$,或是先做 $NT$ 再做 $WA$,只要最終的值相同,則狀態相同 - 所以搜尋演算法通常只需考慮「一個變數一個值」的步驟,而非不同順序 - 只有 $d^n$ 個葉節點 ## 回溯法(Backtracking Search) - 使用 DFS 搜尋答案 - 每次選擇一個變數,然後賦值 - 如果賦值後不滿足約束,則回溯(backtrack)到上一步,重新選擇其他值 ### 提升回溯法的效率 使用 General-purpose Methods(通用策略)來提升回溯法的效率: - 下一個被指派的變數要選哪個? - 要用什麼順序來嘗試值? - 能否提早偵測失敗? - 能否利用問題結構? ### 最少剩餘值域(Minimum Remaining Values, MRV) - 又稱為 Most Constrained Variable Heuristic、fail-first heuristic - 優先選擇剩餘值域最少的變數 - 例如:$WA$ 剩餘值域為 $\{red, green\}$,$NT$ 剩餘值域為 $\{red, green, blue\}$,則選擇 $WA$ ### 度啟發式(Degree Heuristic) - 優先選擇與最多未賦值變數相連的變數。 - 這樣可以最大程度地減少未來的選擇空間,從而提高搜尋效率。 - 當多個變數的 MRV 相同時使用 ### 最少限制值(Least Constraining Value, LCV) - 優先選擇對其他變數限制最少的值。 - 目的是最大程度地保留其他變數的選擇空間,減少未來可能的衝突。 - 例如:如果 $WA$ 的值為 $red$、$NT$ 的值為 $green$,則 - $Q$ 選擇 $red$ 時,$SA$ 有 1 種選擇 - $Q$ 選擇 $green$ 時,$SA$ 有 0 種選擇 ### 向前檢查(Forward Checking) 當某個變數賦值後,立即檢查該賦值對其他未賦值變數的影響 - 如果有變數的值域為空,則立即回溯 - 避免深入無解的分支 ## 局部搜尋 - 從一個完整的狀態開始 - 所有變數皆已賦值 - 但可能不滿足所有約束 - 接著反覆隨機的「小幅度改動」以降低衝突,直到找到合法解或滿意解 - 適合用於大規模的 CSP 問題 - 例如:n 皇后問題、數獨、排程問題 ### 衝突最小化啟發式(Min-Conflicts Heuristic) - 每次隨機選擇一個變數,然後將其值改為使衝突最少的值 ## 問題結構(Problem Structure) 識別特定種類的問題結構可以幫助我們改進效率 ### 樹狀結構(Tree-Structured CSPs) - 若 CSP 的 Constraint Graph 沒有環,則可以在 $O(nd^2)$ 時間內解決 - 一般的 CSP 問題的 worst case 是 $O(d^n)$ ```graphviz digraph map_coloring_graph { rankdir=LR; edge[dir=none]; A -> B C -> B B -> D D -> E D -> F } ``` ### 近似樹結構(Nearly Tree-Structured CSPs) 一個約束圖如果**只需少量修改就能變成樹**,我們就稱它是近似樹結構。 我們可以使用以下方法來解決近似樹結構的 CSP: - 切割集條件法(Cutset Conditioning) - 樹狀分解(Tree Decomposition) ### Cutset Conditioning 找出一小組變數,移除它們後,剩下的約束圖就是一棵樹。這組變數稱為 cutset(切割集)。如以下步驟所示: 1. 找到一組變數 cutset,使得移除它們會讓剩餘圖成為樹。 2. 枚舉 cutset 的所有可能指派(最多 $d^c$ 種,$c$ 為 cutset 大小) 3. 對於每種 cutset 指派: - 套用「樹狀 CSP 解法」來解剩下部分 - 如果成功找到符合的完整解 → 結束! 例如: 當 cutSet 為 $\set{SA}$ 時,剩下的圖為樹狀結構,可以用樹狀 CSP 解法來解決。 ```graphviz digraph map_coloring_graph { rankdir=LR; edge[dir=none]; WA -> NT WA -> SA NT -> SA NT -> Q SA -> Q SA -> NSW SA -> V Q -> NSW V -> NSW T->NSW[style=invis] } ``` ### 樹狀分解 - 將變數拆分成若干個「子問題節點」 - 每個子問題都是一個可以獨立解決 CSP,並且 - 每個變數至少出現在一個子問題中 - 如果變數 $X$ 和 $Y$ 相依,則它們必須在同一個子問題中 - 如果變數 $X$ 出現在兩個子問題,則必須在這兩個節點的路徑上的每一個節點中出現 - 最終的解答是所有子問題的解答的組合 ## 小結 1. **CSP 的基本組成**: - CSP 包含變數、值域和約束,目標是找到滿足所有約束的解。 - 常見應用包括數獨、圖著色問題和排程問題。 2. **回溯法(Backtracking Search)**: - 使用深度優先搜尋(DFS)逐步為變數賦值。 - 提升效率的策略包括: - 最少剩餘值域(MRV) - 度啟發式(Degree Heuristic) - 最少限制值(LCV) - 向前檢查(Forward Checking) 3. **局部搜尋(Local Search)**: - 從完整但可能不合法的解開始,通過隨機小幅度改動來減少衝突。 - 衝突最小化啟發式(Min-Conflicts Heuristic)是局部搜尋中的常用方法。 4. **問題結構(Problem Structure)**: - **樹狀結構(Tree-Structured CSPs)**: - 若約束圖無環,可在 $O(nd^2)$ 時間內高效求解。 - **近似樹結構(Nearly Tree-Structured CSPs)**: - 使用切割集條件法(Cutset Conditioning)或樹狀分解(Tree Decomposition)來處理接近樹結構的問題。