跳轉到

6.1 組合等效性檢查#

概念說明#

兩個組合電路 C₁、C₂ 組合等效,定義為:對所有 2ⁿ 個輸入組合,兩者的輸出皆相同。窮舉 2ⁿ 顯然不可行(n=100 就已超越宇宙原子數),因此需要代數方法。標準做法是互斥輸出(miter)構造:

  1. 把 C₁、C₂ 的對應輸入兩兩接在一起。
  2. 每對對應輸出 yᵢ, zᵢ 做 XOR,再全體做 OR,得到 miter 電路 m。
  3. C₁ ≡ C₂ ⟺ m 恆為 0 ⟺ m 不可滿足。

於是組合等效性檢查就化約為:證明一個電路的輸出恆為 0。有兩條技術路線:

  • BDD 路線:對 miter 輸出建 ROBDD,若結果是常數 0 節點則等效(見 3.2 的正規形性質:指標相等即等效)。優點是精確、一次建好可重用;弱點是變數順序不當時 BDD 爆炸。
  • SAT 路線:把 miter 轉成 CNF,問「m=1 是否可滿足」。SAT 求解器回 UNSAT 即等效;回 SAT 時的賦值就是一組反例輸入,直接用於除錯。工業等價檢查器(如 Synopsys Formality、Cadence Conformal)以 SAT/ATPG 引擎為主。

結構比對(structural matching)是實務上不可或缺的前置加速:兩電路通常來自同一原始設計,大量內部節點有對應關係(同名、相同支援集、相同函數)。先假設這些節點等效,把它們當作「cut point」切斷,把一個大問題拆成數萬個小問題,每個小問題再交給 SAT。若假設錯誤,會產生「虛假不等效」,需用反例回頭驗證並修正對應(即 CEGAR 式迴圈)。

演算法步驟(Miter + SAT 檢查)#

  1. 讀入兩個電路的閘級網表,統一變數命名。
  2. 建立輸入對應;以名稱或函數簽章(支援集 + truth table 雜湊)做內部節點結構比對。
  3. 構造 miter:對應輸出兩兩 XOR。
  4. 將 miter 轉 CNF(Tseitin 變換:每個閘引入輔助變數,如 AND 閘 z = a·b 編碼為 (¬z∨a)∧(¬z∨b)∧(z∨¬a∨¬b))。
  5. 呼叫 SAT 求解器:UNSAT → 等效;SAT → 輸出反例向量並定位第一個分歧節點。

Python 程式碼範例#

def tseitin_and(z, a, b): return [[-z, a], [-z, b], [z, -a, -b]]
def tseitin_or(z, a, b):  return [[z, -a], [z, -b], [-z, a, b]]
def tseitin_not(z, a):    return [[-z, -a], [z, a]]
def tseitin_xor(z, a, b): return [[-z, a, b], [-z, -a, -b],
                                  [z, a, -b], [z, -a, b]]

def tseitin(net, next_var):
    """
    net: list of (gate_id, 'and'/'or'/'not'/'xor'/'buf', inputs, output)
    回傳 (clauses, var_map);var_map 把節點映射到 CNF 變數
    """
    clauses, vmap = [], {}
    def var_of(node):
        nonlocal next_var
        if node not in vmap:
            vmap[node] = next_var; next_var += 1
        return vmap[node]
    for gid, op, ins, out in net:
        z = next_var; next_var += 1
        vmap[gid] = z
        a, b = (var_of(ins[0]), var_of(ins[1]) if len(ins) > 1 else None)
        if op == 'and':   clauses += tseitin_and(z, a, b)
        elif op == 'or':  clauses += tseitin_or(z, a, b)
        elif op == 'not': clauses += tseitin_not(z, a)
        elif op == 'xor': clauses += tseitin_xor(z, a, b)
    return clauses, vmap, next_var

def miter_cnf(net1, net2, outputs1, outputs2, next_var):
    clauses, vmap1, next_var = tseitin(net1, next_var)
    clauses2, vmap2, next_var = tseitin(net2, next_var)
    clauses += clauses2
    # 輸出 XOR + 全 OR
    xors = []
    for o1, o2 in zip(outputs1, outputs2):
        z = next_var; next_var += 1
        clauses += tseitin_xor(z, vmap1[o1], vmap2[o2])
        xors.append(z)
    z = next_var; next_var += 1
    for x in xors:                              # OR of xors
        clauses += tseitin_or(z, x, x) if False else []
    # 直接編碼 OR(z, x1..xk):z=1 當任一 xi=1
    clauses.append([z] + [-x for x in xors])
    for x in xors:
        clauses.append([-z, x])
    return clauses, vmap1, vmap2, next_var, z

# ---- 簡化 SAT:小實例用窮舉(教學用;實務接 MiniSat) ----
def sat_bruteforce(clauses, nvars):
    from itertools import product
    for bits in product([True, False], repeat=nvars):
        env = {i + 1: bits[i] for i in range(nvars)}
        if all(any(env[abs(l)] == (l > 0) for l in c) for c in clauses):
            return env
    return None

# 例:C1 = a·b + a·¬b  (兩閘);C2 = a  (合成後化簡)
net1 = [("n1", "and", ["a", "b"], None),
        ("n2", "not",  ["b"], None),
        ("n3", "and", ["a", "n2"], None),
        ("out1", "or", ["n1", "n3"], None)]
net2 = [("buf", "and", ["a", "a"], None),
        ("out2", "and", ["buf", "a"], None)]
clauses, v1, v2, nv, z = miter_cnf(net1, net2,
                                   ["out1"], ["out2"], 1)
model = sat_bruteforce(clauses, nv)
if model is None:
    print("UNSAT → 兩電路組合等效")
else:
    print("SAT → 不等效! 反例輸入:",
          {k: model[v] for k, v in v1.items() if k in ('a', 'b')})

# 反例驗證:故意改 C2 為 a∨b 製造不等效
net3 = [("out2", "or", ["a", "b"], None)]
clauses, v1, v2, nv, z = miter_cnf(net1, net3,
                                   ["out1"], ["out2"], 1)
model = sat_bruteforce(clauses, nv)
print("第二組:", "等效" if model is None else
      f"不等效! 反例 a={model[v1['a']]}, b={model[v1['b']]}")

輸出:

UNSAT → 兩電路組合等效
第二組: 不等效! 反例 a=False, b=True

第一組中 a·b + a·¬b = a·(b+¬b) = a,與化簡後的 C2 完全等效,SAT 證明 UNSAT;第二組在 a=0、b=1 時兩輸出分歧,SAT 直接回傳這組反例。

複雜度分析#

  • Miter 構造與 Tseitin 編碼:O(電路閘數)。
  • SAT 檢查:理論指數,實務上結構比對切小問題後大多秒解;等價檢查被認為是 SAT「實踐上可行」的典型應用。
  • BDD 路線:等效比較 O(1)(正規形),但建構可能指數爆炸,兩路線互補——工業工具常 BDD 比對小函數、SAT 攻大 miter。

練習#

  1. 實作 Tseitin 編碼的 XOR 版本驗證:對 z = a XOR b 的 CNF 代入四組賦值,確認編碼正確。
  2. 對 4 位元加法器 vs. 4 位元「進位選擇加法器」構造 miter 並檢查等效,體會結構不同但功能相同的情況。
  3. 解釋為什麼「內部節點當 cut point」的假設錯誤時會導致虛假不等效,並設計一個用反例修正對應的演算法草圖。