子圖同構之VF2

Xerrr發表於2020-09-24

子圖同構之VF2

1.子圖同構問題描述

​ 首先描述一下子圖同構是什麼意思,一個圖由一系列節點和一系列連線節點的邊構成,節點和邊都可以有標籤,也就是可以給他們按屬性分類。

​ 精確點:一個圖 G = ( V , E ) G=(V,E) G=(V,E)由集合 V V V和集合 E E E組成, V V V是節點(node)集合, E E E是邊(edge)集合,且 E ⊂ V × V E\subset V\times V EV×V ,用 L v L_v Lv表示節點上的標籤集合, L e L_e Le表示邊上的標籤集合,那麼每個節點對應的標籤由函式(或者說對映) λ v : V → L v \lambda_v:V\rightarrow L_v λv:VLv 確定,每條邊對應的標籤由函式 λ e : E → L e \lambda_e:E\rightarrow L_e λe:ELe 確定。

​ 現在給定兩個圖 G 1 = ( V 1 , E 1 ) G_1=(V_1,E_1) G1=(V1,E1), G 2 = ( V 2 , E 2 ) G_2=(V_2,E_2) G2=(V2,E2) ,其中 G 1 G_1 G1是比較小的圖(我們把它叫做pattern graph), G 2 G_2 G2是比較大的圖(我們把它叫做target graph),用集合 M ⊂ V 1 × V 2 M\sub V_1\times V_2 MV1×V2 表示兩個圖中節點的對應關係。如果節點 u ∈ V 1 u\in V_1 uV1,則 μ ( u ) ∈ V 2 \mu(u)\in V_2 μ(u)V2表示與節點 u u u對應的 G 2 G_2 G2中的節點;如果節點 v ∈ V 2 v\in V_2 vV2,則 ν ( v ) ∈ V 1 \nu(v)\in V_1 ν(v)V1表示與節點 v v v對應的 G 1 G_1 G1中的節點。

G 1 G_1 G1 G 2 G_2 G2
對應關係 u u u μ ( u ) \mu(u) μ(u)
對應關係 μ − 1 ( v ) \mu^{-1} (v) μ1(v) v v v

​ 如果以下6個條件成立,則這兩個圖是子圖同構的。


  1. ∀ u ∈ V 1 ∃ μ ( u ) ∈ V 2 : ( u , μ ( u ) ) ∈ M \forall u\in V_1 \quad \exist \mu(u)\in V_2:(u,\mu(u))\in M uV1μ(u)V2:(u,μ(u))M
  2. ∀ u , u ′ ∈ V 1 u ≠ u ′ ⇒ μ ( u ) ≠ μ ( u ′ ) \forall u,u^{'}\in V_1 \quad u\neq u^{'}\Rightarrow \mu(u)\neq \mu(u^{'}) u,uV1u=uμ(u)=μ(u)
  3. ∀ ( u , u ′ ) ∈ E 1 ∃ ( μ ( u ) , μ ( u ′ ) ) ∈ E 2 ) \forall (u,u^{'})\in E_1 \quad \exist (\mu(u),\mu(u^{'}))\in E_2) (u,u)E1(μ(u),μ(u))E2)
  4. ∀ u , u ′ ∈ V 1 ( μ ( u ) , μ ( u ′ ) ) ∈ E 2 ⇒ ( u , u ′ ) ∈ E 1 \forall u,u^{'} \in V_1 \quad (\mu(u),\mu(u^{'})) \in E_2 \Rightarrow (u,u^{'}) \in E_1 u,uV1(μ(u),μ(u))E2(u,u)E1
  5. ∀ u ∈ V 1 λ V 1 ( u ) = λ V 2 ( μ ( u ) ) \forall u \in V_1 \quad \lambda_{V_1}(u)=\lambda_{V_2}(\mu(u)) uV1λV1(u)=λV2(μ(u))
  6. ∀ ( u , u ′ ) ∈ E 1 λ e 1 ( u , u ′ ) = λ e 2 ( μ ( u ) , μ ( u ′ ) ) \forall (u,u^{'}) \in E_1 \quad \lambda_{e_1}(u,u^{'})=\lambda_{e_2}(\mu(u),\mu(u^{'})) (u,u)E1λe1(u,u)=λe2(μ(u),μ(u))

用人話來解釋一下:

  1. 對於小圖中每個節點,大圖中都要有一個對應的節點與之對應,並且這樣一對一對的節點構成了集合 M M M

  2. 小圖中任意兩個不一樣的節點,他們對應的大圖中的節點不能是同一個;

  3. 小圖中每條邊,大圖中都有一條邊與之對應,並且他們兩端的節點一一對應;

  4. 小圖中任意兩個節點,如果他們對應的大圖中的節點之間有一條邊,那麼小圖中這兩個節點之間也得有條邊;

  5. 每對對應節點的label要相同,也就是這倆節點型別或屬性相同;

  6. 每對對應邊的label要相同,也就是說這倆邊的型別或屬性相同。

​ 綜上所述,子圖同構簡單來說就是,大圖中有一個子結構,長得跟小圖一模一樣,而且這個子結構的節點之間不能多出小圖中不存在的邊來,如果要去掉最後這個而且,就把上面第4個條件去掉~

2.VF2演算法

​ VF2演算法的目標是,給定一個小圖和一個大圖,找出大圖中所有與小圖同構的子圖,這是一個NP-hard問題。整體上,VF3演算法是一個樹搜尋演算法,並且想辦法去儘可能剪枝。搜尋樹上的每個節點都是一個狀態(state),記為 s s s,每個 s s s中包含一系列節點的對映關係,可以想象成一系列key-value對,key都是小圖中的節點,value都是大圖中的節點。搜尋最開始的時候(也就是樹的根節點) s s s中什麼都沒有,隨著搜尋的進行(樹高度的增加), s s s中的key-value對會一對對增加,假如這個狀態中所有的節點對都滿足第一節中的6條約束,我們稱這個狀態為一致狀態(consistent state);如果一個一致狀態包含的小圖中所有的節點,那意味著我們找到了一個大圖的子結構與小圖同構,稱之為目標狀態(goal state);如果一個狀態是不可能再派生出一致狀態的,我們稱之為死亡狀態(dead state)。

​ 那麼現在最大的問題就是兩個:

  1. 這棵搜尋樹怎麼組織?
  2. 怎麼設計剪枝規則?

下面逐個展開~

A. 總體流程介紹

先來介紹一些符號:

M ~ ( s ) \tilde{M}(s) M~(s)表示狀態 s s s中的節點對映集合,則 M ~ ( s ) ⊆ M \tilde{M}(s) \subseteq M M~(s)M

M 1 ~ ( s ) \tilde{M_1}(s) M1~(s)表示 M ~ ( s ) \tilde{M}(s) M~(s)中屬於 G 1 G_1 G1的節點,也就是所有的key,嚴格點: M 1 ~ ( s ) = { u ∈ V 1 : ∃ ( u , v ) ∈ M ~ ( s ) , v ∈ V 2 } \tilde{M_1}(s)=\{u\in V_1:\exist (u,v)\in \tilde{M}(s),v\in V_2\} M1~(s)={uV1:(u,v)M~(s),vV2}

M 2 ~ ( s ) \tilde{M_2}(s) M2~(s)表示 M ~ ( s ) \tilde{M}(s) M~(s)中屬於 G 2 G_2 G2的節點,也就是所有的value,嚴格點: M 2 ~ ( s ) = { v ∈ V 2 : ∃ ( u , v ) ∈ M ~ ( s ) , u ∈ V 1 } \tilde{M_2}(s)=\{v\in V_2:\exist (u,v)\in \tilde{M}(s),u\in V_1\} M2~(s)={vV2:(u,v)M~(s),uV1}

G ~ 1 ( s ) \tilde{G}_1(s) G~1(s)表示僅包含節點在 M 1 ~ ( s ) \tilde{M_1}(s) M1~(s)中的 G 1 G_1 G1的子圖,也就是比 M 1 ~ ( s ) \tilde{M_1}(s) M1~(s)加上了邊;

G ~ 2 ( s ) \tilde{G}_2(s) G~2(s)表示僅包含節點在 M 2 ~ ( s ) \tilde{M_2}(s) M2~(s)中的 G 2 G_2 G2的子圖,也就是比 M 2 ~ ( s ) \tilde{M_2}(s) M2~(s)加上了邊;

μ ~ ( s , u ) \tilde{\mu}(s,u) μ~(s,u)表示 M ~ ( s ) \tilde{M}(s) M~(s)中與 u u u對應的節點,其中 u ∈ V 1 u\in V_1 uV1, μ ~ ( s , u ) ∈ V 2 \tilde{\mu}(s,u)\in V_2 μ~(s,u)V2

μ ~ − 1 ( s , v ) \tilde{\mu}^{-1}(s,v) μ~1(s,v)表示 M ~ ( s ) \tilde{M}(s) M~(s)中與 v v v對應的節點,其中 μ ~ − 1 ( s , v ) ∈ V 1 \tilde{\mu}^{-1}(s,v)\in V_1 μ~1(s,v)V1, v ∈ V 2 v\in V_2 vV2

V 1 V_1 V1 V 2 V_2 V2
對應關係 u u u μ ( s , u ) \mu(s,u) μ(s,u)
對應關係 μ − 1 ( s , v ) \mu^{-1} (s,v) μ1(s,v) v v v

大致看一下整個流程,上虛擬碼~VF2總流程


1: f u n c t i o n    V F 2 ( G 1 , G 2 ) function \ \ VF2(G_1,G_2) function  VF2(G1,G2)

2:        S o l u t i o n s   = ∅ \ \ \ \ \ \ Solutions\ = \empty       Solutions =

3:        M ( s 0 ) = ∅ \ \ \ \ \ \ M(s_0)=\empty       M(s0)=

4:        M a t c h ( M ( s 0 ) , G 2 , G 1 , S o l u t i o n s ) \ \ \ \ \ \ Match(M(s_0),G_2,G_1,Solutions)       Match(M(s0),G2,G1,Solutions)

5:        r e t u r n    S o l u t i o n s \ \ \ \ \ \ return \ \ Solutions       return  Solutions


1: f u n c t i o n    M a t c h ( M ( s ) , G 2 , G 1 , S o l u t i o n s ) function \ \ Match(M(s),G_2,G_1,Solutions) function  Match(M(s),G2,G1,Solutions)

2:        i f    M ( s )    c o v e r s    a l l    t h e    n o d e s    o f    G 1    t h e n \ \ \ \ \ \ if\ \ M(s) \ \ covers\ \ all\ \ the\ \ nodes\ \ of \ \ G_1\ \ then       if  M(s)  covers  all  the  nodes  of  G1  then

3:              A p p e n d ( M ( s ) , S o l u t i o n s ) \ \ \ \ \ \ \ \ \ \ \ \ Append(M(s),Solutions)             Append(M(s),Solutions)

4:        e l s e \ \ \ \ \ \ else       else

5:              P ( s ) = G e t C a n t i t a t e s ( M ( s ) ) \ \ \ \ \ \ \ \ \ \ \ \ P(s)=GetCantitates(M(s))             P(s)=GetCantitates(M(s))

6:              f o r e a c h    p a i r    i n    P ( s ) \ \ \ \ \ \ \ \ \ \ \ \ foreach\ \ pair\ \ in\ \ P(s)             foreach  pair  in  P(s)

7:                    i f    I s F e a s i b l e ( p a i r ) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \ IsFeasible(pair)                   if  IsFeasible(pair)

8:                        M ( s ′ ) = E x t e n d M a t c h ( ( M ( s ) , p a i r ) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ M(s^{'})=ExtendMatch((M(s),pair)                       M(s)=ExtendMatch((M(s),pair)

9:                          M a t c h ( M ( s ′ ) , G 2 , G 1 , S o l u t i o n s ) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Match(M(s^{'}),G_2,G_1,Solutions)                         Match(M(s),G2,G1,Solutions)

10:                        B a c k T r a c k ( M ( s ′ ) , p a i r ) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ BackTrack(M(s^{'}),pair)                       BackTrack(M(s),pair)


​ 一開始, M ~ ( s ) \tilde{M}(s) M~(s)中什麼都沒有,呼叫 M a t c h Match Match函式開始後,先根據當前狀態 s s s和一些與 s s s中節點的連線拓撲關係,獲得節點對集合 P ( s ) P(s) P(s),這是接下來準備加入狀態 s s s候選節點對集合,每一節點對包含一個小圖節點和一個大圖節點。接下來對這個候選節點對集合遍歷,每取出一對節點,先用 I s F e a s i b l e IsFeasible IsFeasible函式判斷其是否可行,如果可以有一些規則提前知道,這一對節點加入必然不可能最終得到一對子圖同構,就可以不繼續往下搜尋;如果該節點對可行,就將這對節點加入狀態 s s s得到狀態 s ′ s^{'} s,並遞迴呼叫 M a t c h Match Match函式繼續往下搜尋。搜完每一分支進行回溯,整個過程就是一個深度優先搜尋過程,狀態 s s s構成了樹的每一個節點, s s s中的節點數相當於搜尋樹的深度。每找到一個子圖同構(也就是深度達到小圖節點數)就把結果加入 S o l u t i o n Solution Solution。因此該演算法的關鍵在於如何設計可行規則,儘可能早地篩除不可能最終獲得子圖同構的節點對,也就是儘可能早、儘可能多地砍掉搜尋樹中的分支。

B 候選節點對

​ 首先我們將一個狀態下不在 M ~ ( s ) \tilde M(s) M~(s)裡的節點分為 P ~ 1 \tilde P_1 P~1, S ~ 1 \tilde S_1 S~1, V ~ 1 \tilde V_1 V~1 P ~ 2 \tilde P_2 P~2, S ~ 2 \tilde S_2 S~2, V ~ 2 \tilde V_2 V~2 ,其中下標1代表是屬於小圖 G 1 G_1 G1的節點子集,下標2代表是屬於大圖 G 2 G_2 G2的節點子集, P P P是predecessor,意思是前驅節點,具體講是至少有一條邊連線到已經匹配的 M ~ ( s ) \tilde M(s) M~(s)集合中節點的所有節點構成的集合,好拗口…重來:一個predecessor節點就是有邊指向 M ~ ( s ) \tilde M(s) M~(s)裡面的節點; S S S P P P相對,是successor,即後繼節點,是從 M ~ ( s ) \tilde M(s) M~(s)中出來被指向的節點構成的集合;最後 V V V是這個圖中既不在 M M M中,又不在 P P P S S S中的節點構成的集合。綜上, M M M是已經匹配的節點集合, P P P S S S是直接和已經匹配的節點相連的節點集合,V是更外圈的節點集合,下面嚴格定義一下~


  1. P ~ 1 ( s ) = { u ∈ V 1 − M ~ 1 ( s ) : ∃ u ′ ∈ M ~ 1 ( s ) : ( u , u ′ ) ∈ E 1 } \tilde P_1(s)=\{u\in V_1-\tilde M_1(s):\exist u^{'}\in \tilde M_1(s):(u,u^{'})\in E_1 \} P~1(s)={uV1M~1(s):uM~1(s):(u,u)E1}
  2. S ~ 1 ( s ) = { u ∈ V 1 − M ~ 1 ( s ) : ∃ u ′ ∈ M ~ 1 ( s ) : ( u ′ , u ) ∈ E 1 } \tilde S_1(s)=\{u\in V_1-\tilde M_1(s):\exist u^{'}\in \tilde M_1(s):(u^{'},u)\in E_1 \} S~1(s)={uV1M~1(s):uM~1(s):(u,u)E1}
  3. V ~ 1 ( s ) = V 1 − M ~ 1 ( s ) − P ~ 1 ( s ) − S ~ 1 ( s ) \tilde V_1(s)=V_1-\tilde M_1(s)-\tilde P_1(s)-\tilde S_1(s) V~1(s)=V1M~1(s)P~1(s)S~1(s)
  4. P ~ 2 ( s ) = { v ∈ V 2 − M ~ 2 ( s ) : ∃ v ′ ∈ M ~ 2 ( s ) : ( v , v ′ ) ∈ E 2 } \tilde P_2(s)=\{v\in V_2-\tilde M_2(s):\exist v^{'}\in \tilde M_2(s):(v,v^{'})\in E_2 \} P~2(s)={vV2M~2(s):vM~2(s):(v,v)E2}
  5. S ~ 2 ( s ) = { v ∈ V 2 − M ~ 2 ( s ) : ∃ v ′ ∈ M ~ 2 ( s ) : ( v ′ , v ) ∈ E 2 } \tilde S_2(s)=\{v\in V_2-\tilde M_2(s):\exist v^{'}\in \tilde M_2(s):(v^{'},v)\in E_2 \} S~2(s)={vV2M~2(s):vM~2(s):(v,v)E2}
  6. V ~ 2 ( s ) = V 2 − M ~ 2 ( s ) − P ~ 2 ( s ) − S ~ 2 ( s ) \tilde V_2(s)=V_2-\tilde M_2(s)-\tilde P_2(s)-\tilde S_2(s) V~2(s)=V2M~2(s)P~2(s)S~2(s)

幾個集合的關係如下圖所示~~~

在這裡插入圖片描述

​ 那麼當前狀態 s s s下,候選節點對集合 P ( s ) P(s) P(s)由哪些節點對構成?任意選一個節點 u ∈ P ~ 1 ( s ) u\in \tilde P_1(s) uP~1(s),再任意選一個節點 v ∈ P ~ 2 ( s ) v\in \tilde P_2(s) vP~2(s),所有這樣的節點構成的節點對 ( u , v ) (u,v) (u,v)都得在 P ( s ) P(s) P(s)裡;任意選一個節點 u ∈ S ~ 1 ( s ) u\in \tilde S_1(s) uS~1(s),再任意選一個節點 v ∈ S ~ 2 ( s ) v\in \tilde S_2(s) vS~2(s),所有這樣的節點構成的節點對 ( u , v ) (u,v) (u,v)也得在 P ( s ) P(s) P(s)裡;如果能構成上面兩種情況的節點對都不存在,任意選一個節點 u ∈ V ~ 1 ( s ) u\in \tilde V_1(s) uV~1(s),再任意選一個節點 v ∈ V ~ 2 ( s ) v\in \tilde V_2(s) vV~2(s),所有這樣的節點構成的節點對 ( u , v ) (u,v) (u,v)組成 P ( s ) P(s) P(s)

​ 接下來從候選節點對集合 P ( s ) P(s) P(s)中挑選一對節點作為當前的候選節點,VF2演算法從中任意拿出一對(其實這裡有很多工作可以做,詳見VF3),然後進入下一步判斷其是否可行。當然,這樣可能會出現在整個搜尋過程中多次到達同一個狀態 s s s的情況,只是每次到達這個狀態 s s s時,對應的 M ~ ( s ) \tilde M(s) M~(s)中的節點對進入的順序不一樣,為了在搜尋過程中不重複到達同一個狀態 s s s,我們在最開始就給小圖中的節點一個優先順序,這個優先順序在VF2中是任意的(這個在VF3中也有很多講究),比如 u 1 ≺ u 2 ≺ . . . u n u_1\prec u_2\prec...u_n u1u2...un,如果當前狀態下 M ~ ( s ) \tilde M(s) M~(s)中已經有小圖節點 u k u_k uk的優先序高於一對節點對中的小圖節點 u j u_j uj的優先序,那麼 u j u_j uj有關的節點對不會被考慮作為候選節點,這就保證了整棵搜尋樹中的狀態不會重複。

C 可行規則

​ 在匹配過程中,每一步選取的節點對 ( u n , v n ) (u_n,v_n) (un,vn)加入到狀態 s s s不一定合適,要麼加入後新的狀態 s ′ s' s不是一致狀態(consistent state),要麼加入後未來幾步不可能達到一致狀態,因此這一搜尋分支就可以被砍掉,不再往下搜尋,並且回溯到上一狀態 s s s並選取下一節點對。我們要用一系列的可行規則來判斷當前選出的候選節點對是否可以加入狀態 s s s達到 s ′ s' s

​ 我們用可行函式 I s F e a s i b l e ( s c , u n , v n ) IsFeasible(s_c,u_n,v_n) IsFeasible(sc,un,vn)來判斷在當前狀態 s c s_c sc下,加入節點對 ( u n , v n ) (u_n,v_n) (un,vn)是否可行。判斷規則主要分為兩類,一類是基於節點和邊的標籤(label),記作 F s F_s Fs,另一類基於圖的拓撲結構,記作 F t F_t Ft。兩類規則都得滿足,因此有:


I s F e a s i b l e ( s c , u n , v n ) = F s ( s c , u n , v n ) ∧ F t ( s c , u n , v n ) IsFeasible(s_c,u_n,v_n)=F_s(s_c,u_n,v_n)\land F_t(s_c,u_n,v_n) IsFeasible(sc,un,vn)=Fs(sc,un,vn)Ft(sc,un,vn)


F s F_s Fs的規則很簡單,就是要保證新加入節點對後,對應節點和邊的label要全部相同:


  1. ∀ u ∈ V 1 λ V 1 ( u ) = λ V 2 ( μ ( u ) ) \forall u \in V_1 \quad \lambda_{V_1}(u)=\lambda_{V_2}(\mu(u)) uV1λV1(u)=λV2(μ(u))
  2. ∀ ( u , u ′ ) ∈ E 1 λ e 1 ( u , u ′ ) = λ e 2 ( μ ( u ) , μ ( u ′ ) ) \forall (u,u^{'}) \in E_1 \quad \lambda_{e_1}(u,u^{'})=\lambda_{e_2}(\mu(u),\mu(u^{'})) (u,u)E1λe1(u,u)=λe2(μ(u),μ(u))

​ 而 F t F_t Ft的規則就複雜一些,當然這也是本演算法剪枝的精髓所在~這部分規則又可以分為三個小部分,第一:將新節點對加入狀態 s s s後,檢查新的狀態 s ′ s' s還是一致狀態,記作 F c F_c Fc;第二,考慮1-lookahead,判斷未來一步是否可能構成一致狀態 s ′ ′ s'' s記作 F l a 1 F_{la1} Fla1;第三,考慮2-lookahead,判斷未來兩步是否可能構成一致狀態 s ′ ′ ′ s''' s,記作 F l a 2 F_{la2} Fla2


F t ( s c , u n , v n ) = F c ( s c , u n , v n ) ∧ F l a 1 ( s c , u n , v n ) ∧ F l a 2 ( s c , u n , v n ) F_t(s_c,u_n,v_n)=F_c(s_c,u_n,v_n)\land F_{la1}(s_c,u_n,v_n)\land F_{la2}(s_c,u_n,v_n) Ft(sc,un,vn)=Fc(sc,un,vn)Fla1(sc,un,vn)Fla2(sc,un,vn)


下面逐個展開~

第一類規則 F c F_c Fc

s c s_c sc已經是一個一致狀態,判斷要新加入的候選節點對 ( u n , v n ) (u_n,v_n) (un,vn)是否可行,需要滿足 s c ∪ ( u n , v n ) s_c\cup (u_n,v_n) sc(un,vn)依然是一致狀態。


F c ( S c , u n , v n ) = ∀ u ′ ∈ S 1 ( u n ) ∩ M ~ 1 ( s c )    ∃ v ′ = μ ~ ( s c , u ′ ) ∈ S 2 ( v n ) ∧ ∀ u ′ ∈ P 1 ( u n ) ∩ M ~ 1 ( s c )    ∃ v ′ = μ ~ ( s c , u ′ ) ∈ P 2 ( v n ) ∧ ∀ v ′ ∈ S 2 ( v n ) ∩ M ~ 2 ( s c )    ∃ u ′ = μ ~ − 1 ( s c , v ′ ) ∈ S 1 ( u n ) ∧ ∀ v ′ ∈ P 2 ( v n ) ∩ M ~ 2 ( s c )    ∃ u ′ = μ ~ − 1 ( s c , v ′ ) ∈ P 1 ( u n ) F_c(S_c,u_n,v_n)= \\ \forall u'\in S_1(u_n)\cap \tilde M_1(s_c)\ \ \exist v'=\tilde \mu(s_c,u')\in S_2(v_n) \\ \land \forall u'\in P_1(u_n)\cap \tilde M_1(s_c)\ \ \exist v'=\tilde \mu(s_c,u')\in P_2(v_n) \\ \land \forall v'\in S_2(v_n)\cap \tilde M_2(s_c)\ \ \exist u'=\tilde \mu ^{-1}(s_c,v')\in S_1(u_n) \\ \land \forall v'\in P_2(v_n)\cap \tilde M_2(s_c)\ \ \exist u'=\tilde \mu ^{-1}(s_c,v')\in P_1(u_n) Fc(Sc,un,vn)=uS1(un)M~1(sc)  v=μ~(sc,u)S2(vn)uP1(un)M~1(sc)  v=μ~(sc,u)P2(vn)vS2(vn)M~2(sc)  u=μ~1(sc,v)S1(un)vP2(vn)M~2(sc)  u=μ~1(sc,v)P1(un)


人話解釋一下:

S 1 ( u n ) S_1(u_n) S1(un) u n u_n un節點的所有後繼節點構成的集合; P 1 ( u n ) P_1(u_n) P1(un) u n u_n un節點的所有前驅節點構成的集合;

S 2 ( v n ) S_2(v_n) S2(vn) v n v_n vn節點的所有後繼節點構成的集合; P 2 ( v n ) P_2(v_n) P2(vn) v n v_n vn節點的所有前驅節點構成的集合。

​ 4條規則就說了一件事:新的節點 u n u_n un與已經匹配上的 M ~ 1 ( s c ) \tilde M_1(s_c) M~1(sc)中節點的關係 和 新的節點 v n v_n vn與已經匹配上的 M ~ 2 ( s c ) \tilde M_2(s_c) M~2(sc)中節點的關係 要一模一樣!不能左邊有右邊沒有或右邊有左邊沒有,也不能亂了順序和邊的方向。

在這裡插入圖片描述
在這裡插入圖片描述

​ 補充:有的問題需求是,小圖中有的邊大圖中必須有,而大圖中有的邊小圖可以沒有,也就是小於等於的關係,那麼就把後兩條規則刪除,也就是最右邊的兩個圖的情況可以被容許。

第二類規則 F l a 1 F_{la1} Fla1


F l a 1 ( s c , u n , v n ) = ∣ P 1 ( u n ) ∩ P ~ 1 ( s c ) ∣ ≤ ∣ P 2 ( v n ) ∩ P ~ 2 ( s c ) ∣ ∧ ∣ P 1 ( u n ) ∩ S ~ 1 ( s c ) ∣ ≤ ∣ P 2 ( v n ) ∩ S ~ 2 ( s c ) ∣ ∧ ∣ S 1 ( u n ) ∩ P ~ 1 ( s c ) ∣ ≤ ∣ S 2 ( v n ) ∩ P ~ 2 ( s c ) ∣ ∧ ∣ S 1 ( u n ) ∩ S ~ 1 ( s c ) ∣ ≤ ∣ S 2 ( v n ) ∩ S ~ 2 ( s c ) ∣ F_{la1}(s_c,u_n,v_n)=\\ |P_1(u_n)\cap \tilde P_1(s_c)|\le |P_2(v_n)\cap \tilde P_2(s_c)| \\ \land |P_1(u_n)\cap \tilde S_1(s_c)|\le |P_2(v_n)\cap \tilde S_2(s_c)| \\ \land |S_1(u_n)\cap \tilde P_1(s_c)|\le |S_2(v_n)\cap \tilde P_2(s_c)| \\ \land |S_1(u_n)\cap \tilde S_1(s_c)|\le |S_2(v_n)\cap \tilde S_2(s_c)| Fla1(sc,un,vn)=P1(un)P~1(sc)P2(vn)P~2(sc)P1(un)S~1(sc)P2(vn)S~2(sc)S1(un)P~1(sc)S2(vn)P~2(sc)S1(un)S~1(sc)S2(vn)S~2(sc)


​ 這一類約束主要考慮與當前狀態 s c s_c sc中的節點直接相連的節點( P , S P,S P,S集合)與新的節點對 ( u n , v n ) (u_n,v_n) (un,vn)間的關係。現在考慮的是3部分節點,1是已經在 M ( s c ) M(s_c) M(sc)中的節點,即已經匹配了的;2是新的候選節點;3是 P , S P,S P,S集合中的節點。3的節點中,與1和2的關係可以分成四類,分別對應上述4條規則,每一類關係的節點數量都要滿足:小圖節點數量不大於大圖節點數量,若小圖某一類的節點數大於大圖了,說明未來不可能形成一致狀態,因為未來必然會有小圖中邊,在大圖中找不到。

在這裡插入圖片描述

第三類規則 F l a 2 F_{la2} Fla2


F l a 2 ( s c , u n , v n ) = ∣ P 1 ( u n ) ∩ V ~ 1 ( s c ) ∣ ≤ ∣ P 2 ( v n ) ∩ V ~ 2 ( s c ) ∣ ∧ ∣ S 1 ( u n ) ∩ V ~ 1 ( s c ) ∣ ≤ ∣ S 2 ( v n ) ∩ V ~ 2 ( s c ) ∣ F_{la2}(s_c,u_n,v_n)= \\ |P_1(u_n)\cap \tilde V_1(s_c)|\le |P_2(v_n)\cap \tilde V_2(s_c)| \\ \land |S_1(u_n)\cap \tilde V_1(s_c)|\le |S_2(v_n)\cap \tilde V_2(s_c)| Fla2(sc,un,vn)=P1(un)V~1(sc)P2(vn)V~2(sc)S1(un)V~1(sc)S2(vn)V~2(sc)


​ 這一類約束主要考慮與當前狀態 s c s_c sc中的節點不直接相連的節點( V V V集合)與新的節點對 ( u n , v n ) (u_n,v_n) (un,vn)間的關係。現在考慮的是3部分節點,1是已經在 M ( s c ) M(s_c) M(sc)中的節點,即已經匹配了的;2是新的候選節點;3是 V V V集合中的節點。3的節點中,與1和2的關係可以分成2類,分別對應上述2條規則,每一類關係的節點數量都要滿足:小圖節點數量不大於大圖節點數量,若小圖某一類的節點數大於大圖了,說明未來不可能形成一致狀態,因為未來必然會有小圖中邊,在大圖中找不到。

在這裡插入圖片描述

​ 上述三類規則其實是把新節點對 ( u n , v n ) (u_n,v_n) (un,vn)的度分成三部分,第一部分是與 M ( s ) M(s) M(s)中節點的連線;第二部分是與 P ( s ) 、 V ( s ) P(s)、V(s) P(s)V(s)中節點的連線,即1-lookahead;第三部分是與 V ( s ) V(s) V(s)中節點的連線,即2-lookahead。這三類連線又可以分為入度和出度,與其連線的節點又可以按分組分開,其中第一部分 M ( s ) M(s) M(s)中已經匹配上的節點分組一定相同,因此可以不考慮分組。這樣分類後,每一類度的數量都要滿足,小圖不大於大圖,否則將不可能同構,其中第一類比較特殊,必須完全相同才能同構,當然也有隻需要小於等於的需求,這類需求嚴格意義上已經不是子圖同構了。

3 總結

​ VF演算法的搜尋樹其實跟Ullmann演算法是一樣的,只不過Ullmann用矩陣表示每一個狀態 s s s,VF2演算法最核心的就是可行規則,提前篩除了很多不必要的分支,而後面的VF3演算法在VF2的基礎上加入了候選節點選擇時的順序,可以在更早的時候剪掉更多大分支,並且在可行規則中給節點分了類,進一步加大剪枝力度~

相關文章