子图同构之Ullmann

子图同构之Ullmann

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 ullmann算法子图同构判定方法

​ 首先,图 G 1 = ( V 1 , E 1 ) G_1=(V_1,E_1) G1=(V1,E1)的邻接矩阵为 A = [ a i j ] A=[a_{ij}] A=[aij],图 G 2 = ( V 2 , E 2 ) G_2=(V_2,E_2) G2=(V2,E2)的邻接矩阵为 B = [ b i j ] B=[b_{ij}] B=[bij],其中邻接矩阵构建规则如下:


x i j = { 1       存在节点 i → 节点 j 的边 0   不存在节点 i → 节点 j 的边 x_{ij}=\left\{ \begin{aligned} 1 \ \ \ \ \ \ 存在节点i\rightarrow 节点j的边 \\ 0 \ \ 不存在节点i\rightarrow 节点j的边 \end{aligned} \right. xij={1      存在节点i节点j的边0  不存在节点i节点j的边


G 1 G_1 G1 p 1 p_1 p1个节点和 q 1 q_1 q1条边, G 2 G_2 G2 p 2 p_2 p2个节点和 q 2 q_2 q2条边。

定义大小为 p 1 × p 2 p_1\times p_2 p1×p2的0-1矩阵 M = [ m i j ] M=[m_{ij}] M=[mij],表示 G 1 G_1 G1中节点和 G 2 G_2 G2中节点的一个映射,若 m i j = 1 m_{ij}=1 mij=1则表示 G 2 G_2 G2中的节点 j j j G 1 G_1 G1中的节点 i i i构成一对节点对。

定义矩阵 C = [ c i j ] = M B M T C=[c_{ij}]=MBM^T C=[cij]=MBMT,如果满足如下条件,则矩阵 M M M确定了一个 G 1 G_1 G1 G 2 G_2 G2的子图同构,也就是在 G 2 G_2 G2中找到了一个跟 G 1 G_1 G1一模一样的子结构:


( ∀ i ∀ j ) 1 ≤ i ≤ q 1 , 1 ≤ j ≤ q 1 ( a i j = 1 ) ⇒ ( c i j = 1 ) (\forall i\forall j)_{1\le i\le q_1,1\le j\le q_1} (a_{ij}=1)\Rightarrow(c_{ij}=1) (ij)1iq1,1jq1(aij=1)(cij=1)


解释一下:

​ 矩阵 M M M要确定一组节点的对应关系使小图和大图中对应节点构成的子图一模一样,必须满足:每一行正好有一个1,每一列最多有1个1,因为小图中每个节点都要在大图中找到一个对应的节点,而大图中的节点最多可以和小图中一个节点对应。

​ 矩阵 C = M B M T C=MBM^T C=MBMT,对矩阵 B B B做行列变换,左乘行变换,右乘列变换,先左乘 M M M再右乘 M T M^T MT实则是交换了一系列节点编号(或顺序), C C C矩阵表达了一个将大图中的节点顺序进行一系列交换,排在最前面的 q 1 q_1 q1个节点构成的子结构,该结构正好和小图节点可以一一对应,并且小图中有的边,大图的这个子结构中也有,则找到了一个同构子图,下面举个简单例子:

在这里插入图片描述


A = A 1 ^ 2 ^ 3 ^ 1 ^ 0 1 0 2 ^ 0 0 1 3 ^ 1 0 0             B = B 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 0 1 0 0 2 ^ 0 0 1 0 3 ^ 1 0 0 1 4 ^ 0 1 0 0 A=\begin{array}{c|cccc} A & \hat 1 & \hat 2 & \hat 3 \\ \hline \hat 1 & 0 & 1 & 0 \\ \hat 2 & 0 & 0 & 1 \\ \hat 3 & 1 & 0 & 0 \\ \end{array} \ \ \ \ \ \ \ \ \ \ \ B=\begin{array}{c|cccc} B & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 0 & 1 & 0 & 0 \\ \hat 2 & 0 & 0 & 1 & 0 \\ \hat 3 & 1 & 0 & 0 & 1 \\ \hat 4 & 0 & 1 & 0 & 0 \\ \end{array} A=A1^2^3^1^0012^1003^010           B=B1^2^3^4^1^00102^10013^01004^0010


有2个同构形式:

在这里插入图片描述


M 1 = M 1 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 1 0 0 0 2 ^ 0 1 0 0 3 ^ 0 0 1 0             M 2 = M 2 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 0 0 0 1 2 ^ 0 1 0 0 3 ^ 0 0 1 0 M_1=\begin{array}{c|cccc} M_1 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 1 & 0 & 0 & 0 \\ \hat 2 & 0 & 1 & 0 & 0 \\ \hat 3 & 0 & 0 & 1 & 0 \\ \end{array} \ \ \ \ \ \ \ \ \ \ \ M_2=\begin{array}{c|cccc} M_2 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 0 & 0 & 0 & 1 \\ \hat 2 & 0 & 1 & 0 & 0 \\ \hat 3 & 0 & 0 & 1 & 0 \\ \end{array} M1=M11^2^3^1^1002^0103^0014^000           M2=M21^2^3^1^0002^0103^0014^100


第一个: C 1 = M 1 B M 1 T C_1=M_1BM_1^T C1=M1BM1T,首先 M 1 B = [ 0 1 0 0 0 0 1 0 1 0 0 1 ] M_1B=\begin{bmatrix} 0&1&0&0\\0&0&1&0\\1&0&0&1\end{bmatrix} M1B= 001100010001 ,即取前三行并且没有换位置,再右乘 M 1 T M_1^T M1T C 1 = [ 0 1 0 0 0 1 1 0 0 ] C_1=\begin{bmatrix} 0&1&0\\0&0&1\\1&0&0\end{bmatrix} C1= 001100010 ,即取前三列并且没有换位置,此时 A A A中为1的位置 C 1 C_1 C1中也都为1,也就是 A A A中有的边 C 1 C_1 C1中也都有, M 1 M_1 M1表达了:将图 B B B取前三个节点,使 A 1 − B 1 , A 2 − B 2 , A 3 − B 3 A1-B1,A2-B2,A3-B3 A1B1,A2B2,A3B3一一对应,即得到一个子图同构的解。

第二个: C 2 = M 2 B M 2 T C_2=M_2BM_2^T C2=M2BM2T,首先 M 2 B = [ 0 1 0 0 0 0 1 0 1 0 0 1 ] M_2B=\begin{bmatrix} 0&1&0&0\\0&0&1&0\\1&0&0&1\end{bmatrix} M2B= 001100010001 ,即依次取 B B B的第4行,第2行,第3行,再右乘 M 2 T M_2^T M2T C 2 = [ 0 1 0 0 0 1 1 0 0 ] C_2=\begin{bmatrix} 0&1&0\\0&0&1\\1&0&0\end{bmatrix} C2= 001100010 ,即即依次取 M 2 B M_2B M2B的第4列,第2列,第3列,此时 A A A中为1的位置 C 2 C_2 C2中也都为1,也就是 A A A中有的边 C 2 C_2 C2中也都有, M 2 M_2 M2表达了:将图 B B B取第4,第2,第3个节点,使 A 1 − B 4 , A 2 − B 2 , A 3 − B 3 A1-B4,A2-B2,A3-B3 A1B4,A2B2,A3B3一一对应,即得到一个子图同构的解。

3 ullmann算法状态空间

​ 要找出所有的子图同构形式,一个很自然的想法就是遍历所有可能的 M M M,一个个判断是否符合上面的判定公式。

​ 首先,构造大小为 p 1 × p 2 p_1\times p_2 p1×p2的0-1矩阵 M 0 = [ m i j 0 ] M^0=[m^0_{ij}] M0=[mij0],其中
m i j 0 = { 1    大图第 j 个节点的度不小于小图第 i 个节点的度 0        大图第 j 个节点的度小于小图第 i 个节点的度 m^0_{ij}=\left\{ \begin{aligned} 1 \ \ \ 大图第j个节点的度不小于小图第i个节点的度 \\ 0 \ \ \ \ \ \ \ 大图第j个节点的度小于小图第i个节点的度 \end{aligned} \right. mij0={1   大图第j个节点的度不小于小图第i个节点的度0       大图第j个节点的度小于小图第i个节点的度
​ 然后就按一定顺序产生矩阵 M M M,要求是, M M M中为1的位置, M 0 M^0 M0中也必须为1,并且还得满足每一行正好有一个1,每一列最多有1个1。也就是说, M 0 M^0 M0列出了所有可能匹配上的节点对,而我们每次从中找出一组进行验证。

上面的例子中,小图节点的度均为2,大图节点的度分别为2,3,3,2。因此构造 M 0 M^0 M0如下:
M 0 = M 0 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 1 1 1 1 2 ^ 1 1 1 1 3 ^ 1 1 1 1 M_0=\begin{array}{c|cccc} M_0 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 1 & 1 & 1 & 1 \\ \hat 2 & 1 & 1 & 1 & 1 \\ \hat 3 & 1 & 1 & 1 & 1 \\ \end{array} M0=M01^2^3^1^1112^1113^1114^111
然后进行深度优先搜索,定义状态 s s s是一个中间状态,也就是选取候选矩阵时确定某几行的状态,由 s s s构成搜索树, s 0 s_0 s0对应初始矩阵 M 0 M_0 M0 s i j s_i^j sij对应一个矩阵, i i i表示已经选取的矩阵行数(前几行),也相当于 s i j s_i^j sij在搜索树中的深度, j j j表示该深度下第几种可能。
s 0 = s 0 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 1 1 1 1 2 ^ 1 1 1 1 3 ^ 1 1 1 1 s 1 1 = s 1 1 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 1 0 0 0 2 ^ 1 1 1 1 3 ^ 1 1 1 1          s 2 1 = s 2 1 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 1 0 0 0 2 ^ 0 1 0 0 3 ^ 1 1 1 1          s 3 1 = s 3 1 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 1 0 0 0 2 ^ 0 1 0 0 3 ^ 0 0 1 0 s 1 1 = s 1 1 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 1 0 0 0 2 ^ 1 1 1 1 3 ^ 1 1 1 1          s 2 1 = s 2 1 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 1 0 0 0 2 ^ 0 1 0 0 3 ^ 1 1 1 1          s 3 2 = s 3 2 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 1 0 0 0 2 ^ 0 1 0 0 3 ^ 0 0 0 1 s 1 1 = s 1 1 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 1 0 0 0 2 ^ 1 1 1 1 3 ^ 1 1 1 1          s 2 2 = s 2 2 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 1 0 0 0 2 ^ 0 0 1 0 3 ^ 1 1 1 1          s 3 3 = s 3 3 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 1 0 0 0 2 ^ 0 0 1 0 3 ^ 0 1 0 0 s 1 1 = s 1 1 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 1 0 0 0 2 ^ 1 1 1 1 3 ^ 1 1 1 1          s 2 2 = s 2 2 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 1 0 0 0 2 ^ 0 0 1 0 3 ^ 1 1 1 1          s 3 4 = s 3 4 1 ^ 2 ^ 3 ^ 4 ^ 1 ^ 1 0 0 0 2 ^ 0 0 1 0 3 ^ 0 0 0 1 . . . s_0=\begin{array}{c|cccc} s_0 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 1 & 1 & 1 & 1 \\ \hat 2 & 1 & 1 & 1 & 1 \\ \hat 3 & 1 & 1 & 1 & 1 \\ \end{array} \\ s_1^1=\begin{array}{c|cccc} s_1^1 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 1 & 0 & 0 & 0 \\ \hat 2 & 1 & 1 & 1 & 1 \\ \hat 3 & 1 & 1 & 1 & 1 \\ \end{array} \ \ \ \ \ \ \ \ s_2^1=\begin{array}{c|cccc} s_2^1 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 1 & 0 & 0 & 0 \\ \hat 2 & 0 & 1 & 0 & 0 \\ \hat 3 & 1 & 1 & 1 & 1 \\ \end{array} \ \ \ \ \ \ \ \ s_3^1=\begin{array}{c|cccc} s_3^1 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 1 & 0 & 0 & 0 \\ \hat 2 & 0 & 1 & 0 & 0 \\ \hat 3 & 0 & 0 & 1 & 0 \\ \end{array} \\ s_1^1=\begin{array}{c|cccc} s_1^1 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 1 & 0 & 0 & 0 \\ \hat 2 & 1 & 1 & 1 & 1 \\ \hat 3 & 1 & 1 & 1 & 1 \\ \end{array} \ \ \ \ \ \ \ \ s_2^1=\begin{array}{c|cccc} s_2^1 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 1 & 0 & 0 & 0 \\ \hat 2 & 0 & 1 & 0 & 0 \\ \hat 3 & 1 & 1 & 1 & 1 \\ \end{array} \ \ \ \ \ \ \ \ s_3^2=\begin{array}{c|cccc} s_3^2 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 1 & 0 & 0 & 0 \\ \hat 2 & 0 & 1 & 0 & 0 \\ \hat 3 & 0 & 0 & 0 & 1 \\ \end{array} \\ s_1^1=\begin{array}{c|cccc} s_1^1 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 1 & 0 & 0 & 0 \\ \hat 2 & 1 & 1 & 1 & 1 \\ \hat 3 & 1 & 1 & 1 & 1 \\ \end{array} \ \ \ \ \ \ \ \ s_2^2=\begin{array}{c|cccc} s_2^2 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 1 & 0 & 0 & 0 \\ \hat 2 & 0 & 0 & 1 & 0 \\ \hat 3 & 1 & 1 & 1 & 1 \\ \end{array} \ \ \ \ \ \ \ \ s_3^3=\begin{array}{c|cccc} s_3^3 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 1 & 0 & 0 & 0 \\ \hat 2 & 0 & 0 & 1 & 0 \\ \hat 3 & 0 & 1 & 0 & 0 \\ \end{array} \\ s_1^1=\begin{array}{c|cccc} s_1^1 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 1 & 0 & 0 & 0 \\ \hat 2 & 1 & 1 & 1 & 1 \\ \hat 3 & 1 & 1 & 1 & 1 \\ \end{array} \ \ \ \ \ \ \ \ s_2^2=\begin{array}{c|cccc} s_2^2 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 1 & 0 & 0 & 0 \\ \hat 2 & 0 & 0 & 1 & 0 \\ \hat 3 & 1 & 1 & 1 & 1 \\ \end{array} \ \ \ \ \ \ \ \ s_3^4=\begin{array}{c|cccc} s_3^4 & \hat 1 & \hat 2 & \hat 3 & \hat 4 \\ \hline \hat 1 & 1 & 0 & 0 & 0 \\ \hat 2 & 0 & 0 & 1 & 0 \\ \hat 3 & 0 & 0 & 0 & 1 \\ \end{array} \\ ... s0=s01^2^3^1^1112^1113^1114^111s11=s111^2^3^1^1112^0113^0114^011        s21=s211^2^3^1^1012^0113^0014^001        s31=s311^2^3^1^1002^0103^0014^000s11=s111^2^3^1^1112^0113^0114^011        s21=s211^2^3^1^1012^0113^0014^001        s32=s321^2^3^1^1002^0103^0004^001s11=s111^2^3^1^1112^0113^0114^011        s22=s221^2^3^1^1012^0013^0114^001        s33=s331^2^3^1^1002^0013^0104^000s11=s111^2^3^1^1112^0113^0114^011        s22=s221^2^3^1^1012^0013^0114^001        s34=s341^2^3^1^1002^0003^0104^001...
因此构成了一棵由状态 s s s构成的树:

在这里插入图片描述

​ 当深度达到与小图节点数相同时,也就得到了一个候选矩阵 M M M,再用第2节中的判别公式判断一下就可以了。这里可以看到,其实深度就是当下考虑的小图节点数,当前行选择的1的位置也就是选择大图中对应的节点。

​ 用深度优先搜索遍历完整棵树后,就找到了所有的同构子图,这也就是在 M 0 M^0 M0下的暴力搜索。

4 剪枝

​ 在暴力搜索的基础上,可以根据很多信息比如图的拓扑结构进行剪枝,只要我们确定小图第 i i i个节点和大图第 j j j个节点对应不可能构成子图同构,就把 M 0 M^0 M0 m i j m_{ij} mij设置为0。这是一开始给的约束,比如第三节中给的约束:如果小图中一个节点的度大于大图中某个节点的度,那么这两个节点不可能对应上,算法一开始就把这种情况约束掉了,不需要进行搜索。

​ 至于剪枝规则,后来提出的很多算法有非常优越的剪枝效果,比如VF2、VF3等,后续还会总结一下这几个算法,ullmann算法可以说是子图同构的鼻祖,理解这个算法可以对子图同构问题以及树搜索和剪枝有更好的理解,有助于更好地理解后来大牛们提出的众多算法~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值