DFA最小化 -- Hopcroft算法 Python实现


问了 30 个技术群,也问了无数的前辈,真是各种不礼貌,吃了无数闭门羹,还是自己看着有点眉目了

还有 wiki 的伪代码看了总觉得奇怪,于是看了同一页面其他语言翻译过来的伪代码,

发现葡萄牙语和俄罗斯语那里的 if 判断都还缺少一个条件


国内的资料比较少,这几份学习资料不错,比我稀里糊涂的思路要好,分享下:

http://www.liafa.univ-paris-diderot.fr/~carton/Enseignement/Complexite/

ENS/Redaction/2008-2009/yingjie.xu.pdf

http://www8.cs.umu.se/kurser/TDBC92/VT06/final/1.pdf

http://arxiv.org/pdf/1010.5318.pdf



对于一个确定型自动机 D = (Q, Σ, δ, q0, F),Q 的一系列恒等关系 ρi (i ≥ 0) 被定义为:

ρ0 = {(p, q)|p, q ∈ F} ∪ {(p, q)|p, q ∈ Q ? F},

ρi+1 = {(p, q) ∈ ρi|(?a ∈ Σ)(δ(p, a), δ(q, a)) ∈ ρi}.


ρi有如下关系:

ρ0 ? ρ1 ? · · · .

若 ρi = ρi+1 则对于 ρi = ρj (j > i).

存在 0 ≤ k ≤ |Q| 满足 ρk = ρk+1.


对于 ρi ≠ ρi+1,存在以下性质Equation 1

ρi ≠ ρi+1    ? (?p, q ∈ Q, a ∈ Σ) (p, q) ∈ ρi and (δ(p, a), δ(q, a)) ? ρi

? (?U ∈ Q/ρi , a ∈ Σ) p, q ∈ U and (δ(p, a), δ(q, a)) ? ρi

? (?U, V ∈ Q/ρi , a ∈ Σ) p, q ∈ U and δ(p, a) ∈ V and δ(q, a) ? V

? (?U, V ∈ Q/ρi , a ∈ Σ) δ(U, a) ∩ V ≠ ? and δ(U, a) ? V



算法抽象:

1: Q/θ ← {F, Q ? F}
2: while (?U, V ∈ Q/θ, a ∈ Σ) s.t.
Equation 1 holds do
3: Q/θ ← (Q/θ ? {U}) ∪ {U ∩ δ^-1(V, a), U ? U ∩ δ^-1(V, a)}
4: end while


算法细化:

1:W ← {F, Q ? F}    # 有些版本上只是 W ← {F }

2: P ← {F, Q ? F}

3: while W is not empty do

4:     select and remove S from W

5:     for all a ∈ Σ do

6:         la ← δ^-1(S, a)

7:         for all R in P such that R ∩ la ≠ ? and R ? la do

8:             partition R into R1 and R2: R1 ← R ∩ la and R2 ← R ? R1

9:             replace R in P with R1 and R2

10:           if R ∈ W then

11:               replace R in W with R1 and R2

12:           else

13:                 if |R1| ≤ |R2| then

14:                     add R1 to W

15:                 else

16:                     add R2 to W

17:                 end if

18:             end if

19:         end for

20:     end for

21: end while


复杂度:

O(n log n)


还有一个优化的代码:

1: P = {F, Q ? F}

2:     for all a ∈ A do

3:         Add((min(F, Q ? F), a), S)

4:     while S ≠ ? do

5:         get (C, a) from S (we extract (C, a) according to the

strategy associated with S: FIFO/LIFO/...)

6:         for each B ∈ P split by (C, a) do

7:             B′, B′′ are the sets resulting from splitting of B w.r.t. (C, a)

8:             Replace B in P with both B′ and B′′

9:             for all b ∈ A do

10:                if (B, b) ∈ S then

11:                    Replace (B, b) by (B′, b) and (B′′, b) in S

12:                else

13:                    Add((min(B′,B′′), b), S)



找出无用状态:

state_graph1 = {
    'total_states': [ 'A', 'B', 'C', 'D', 'E' ],
    'initial_states': [ 'A' ],
    'termination_states': [ 'D' ],
    'state_transition_map': {
        'A': { 'a': 'B', 'b': 'C' },
        'B': { 'a': 'B', 'b': 'D' },
        'C': { 'a': 'B' },
        'E': { 'a': 'E', 'b': 'E', },
        'D': { 'a': 'B' },
    },
    'cins': [ 'a', 'b' ],
}


def get_unreachable_states( G ):
    reachable_states      = set( G['initial_states'] )
    new_states            = set( G['initial_states'] )
    total_states          = set( G['total_states'] )
    cins                  = G['cins']
    state_transition_map  = G['state_transition_map']
    
    while True:
        temp_set = set()
        for state in new_states:
            for char in cins:
                try:
                    next_state = state_transition_map[state][char]
                    temp_set.update( next_state )
                except KeyError:
                    pass

        new_states = temp_set - reachable_states
        reachable_states.update( temp_set )
        if new_states == set():
            break

    unreachable_states = total_states - reachable_states
    return unreachable_states


print get_unreachable_states( state_graph1 )

Hopcroft:

import random
from copy import deepcopy

state_graph1 = {
    'total_states': [ '1', '2', '3', '4', '5', '6', '7' ],
    'initial_states': [ '1' ],
    'termination_states': [ '6', '7' ],
    'state_transition_map': {
        '1': { 'a': '3', 'b': '2' },
        '2': { 'a': '4', 'b': '2' },
        '3': { 'c': '3', 'b': '6', 'd': '5' },
        '4': { 'b': '7', 'd': '5', 'c': '3' },
        '5': { 'a': '4' },
        '6': { 'b': '6' },
        '7': { 'b': '6' },
    },
    'cins': [ 'a', 'b', 'c', 'd' ],    
}

state_graph2 = {
    'total_states': [ 'A', 'B', 'C', 'D', 'E', 'F', 'S' ],
    'initial_states': [ 'A' ],
    'termination_states': [ 'C', 'D', 'E', 'F' ],
    'state_transition_map': {
        'S': { 'a': 'A', 'b': 'B' },
        'A': { 'a': 'C', 'b': 'B' },
        'B': { 'a': 'A', 'b': 'D' },
        'C': { 'a': 'C', 'b': 'E' },
        'D': { 'a': 'F', 'b': 'D' },
        'E': { 'a': 'F', 'b': 'D' },
        'F': { 'a': 'C', 'b': 'E' },
    },
    'cins': [ 'a', 'b' ],    
}


state_graph3 = {
    'total_states': [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' ],
    'initial_states': [ 'A' ],
    'termination_states': [ 'C' ],
    'state_transition_map': {
        'A': { '0': 'B', '1': 'F' },
        'B': { '0': 'G', '1': 'C' },
        'C': { '0': 'A', '1': 'C' },
        'D': { '0': 'C', '1': 'G' },
        'E': { '0': 'H', '1': 'F' },
        'F': { '0': 'C', '1': 'G' },
        'G': { '0': 'G', '1': 'E' },
        'H': { '0': 'G', '1': 'C' }
    },
    'cins': [ '0', '1' ],    
}


def hopcroft_algorithm( G ):
    cins                   = set( G['cins'] )
    termination_states     = set( G['termination_states'] ) 
    total_states           = set( G['total_states'] )
    state_transition_map   = G['state_transition_map']
    not_termination_states = total_states - termination_states

    def get_source_set( target_set, char ):
        source_set = set()
        for state in total_states:
            try:
                if state_transition_map[state][char] in target_set:
                    source_set.update( state )
            except KeyError:
                pass
        return source_set

    P = [ termination_states, not_termination_states ]
    W = [ termination_states, not_termination_states ]

    while W:
        
        A = random.choice( W )
        W.remove( A )

        for char in cins:
            X = get_source_set( A, char )
            P_temp = []
            
            for Y in P:
                S  = X & Y
                S1 = Y - X
                
                if len( S ) and len( S1 ):
                    P_temp.append( S )
                    P_temp.append( S1 )
                    
                    if Y in W:
                        W.remove( Y )    
                        W.append( S )
                        W.append( S1 )
                    else:
                        if len( S ) <= len( S1 ):
                            W.append( S )
                        else:
                            W.append( S1 )
                else:
                    P_temp.append( Y )
            P = deepcopy( P_temp )
    return P


print hopcroft_algorithm( state_graph1 )
print hopcroft_algorithm( state_graph2 )
print hopcroft_algorithm( state_graph3 )


岛津义弘:

“真田幸村,这片 ‘ 战国 ’ 的土地上有太多的冷漠和争斗,

一个人想要在这样的 ‘ 乱世 ’ 中心存温柔,他前进的道路定然会很痛苦,

但是最后能走到 ‘ 武 ’ 之巅峰的人,却往往又都是那样内心温柔的人。

因为这份温柔能够让人变得很强壮。

希望你即便面对的是你的敌人,挥舞自己的 ‘ 双枪 ’ 时,也不要失去这份温柔。”


DFA最小化 -- Hopcroft算法 Python实现


DFA最小化 -- Hopcroft算法 Python实现,布布扣,bubuko.com

DFA最小化 -- Hopcroft算法 Python实现

上一篇:Effective C++:条款36:绝不重新定义继承而来的non-virtual函数


下一篇:Springmvc中@RequestMapping 属性用法归纳