子图同构算法Ullmann早在1976年就提出来了,大家有兴趣可以自己去搜索下原文看看。这里我就简要的阐述一下。
给定两个图Q 和 G, 它们相应的矩阵分别是和.我们的目标就是找到矩阵
算法步骤:
Step1. Setup matrix Mn×m , such that M[i][j]=1, if 1) the i-th vertex in Q hasthe same label as the j-th vertex in G; and 2) the i-th vertex has smallervertex degree than the j-th vertex in G.
Step2.MatrixesM are generated by systematically changing to 0 all but one of the 1’s in eachof the rows of M, subject to the definitory condition that no column of amatrix M may contain more than one 1.
Step3.Verify matrix M’ by the following equation
为了提高算法的效率,采用了如下的Refinement。
Refinement:
Letthe i-th vertex v in Q corresponds to the j-th vertex u in G.Each neighbor vertex of
v in Q must correspond to some neighbor vertexof u in G. Otherwise,
vcannot correspond to u.
1. Considering the matrix M, for each 1 in M, we refine it by the followingequation. If fails, change 1 to 0 in M.
2. If there exists at least one row (in M) having no 1, we report no subgraphisomorphism from Q to G.
接下来就直接粘贴代码了。
package ucas.iie.graph.action; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import ucas.iie.graph.bean.EdgeBean; import ucas.iie.graph.bean.GraphBean; import ucas.iie.graph.bean.VertexBean; public class IsomorphismImpl { private ArrayList<GraphBean> query_g;// 查询的子图 private ArrayList<GraphBean> mydb_g;// 图的总数据 public IsomorphismImpl() { query_g = new ArrayList<GraphBean>(); mydb_g = new ArrayList<GraphBean>(); } /** * * @param query * @param db * @return 返回初始的矩阵M0 */ public int[][] getMatrixM(GraphBean query, GraphBean db) { int row = query.getvList().size(); int column = db.getvList().size(); int[][] M0 = new int[row][column]; // System.out.println("M0:"); for (int i = 0; i < row; i++) { for (int j = 0; j < column; j++) { String vi = query.getvList().get(i).getVertex(); String vj = db.getvList().get(j).getVertex(); if (db.getVDegree(vj) >= query.getVDegree(vi)) M0[i][j] = 1; else M0[i][j] = 0; // System.out.print(M0[i][j] + " "); } // System.out.println(""); } return M0; } public ArrayList<GraphBean> getQuery_g() { return query_g; } public void setQuery_g(ArrayList<GraphBean> query_g) { this.query_g = query_g; } public ArrayList<GraphBean> getMydb_g() { return mydb_g; } public void setMydb_g(ArrayList<GraphBean> mydb_g) { this.mydb_g = mydb_g; } /** * * @param queryFile * 查询子图的路径 * @param dbFile * 图的总数据路径 * @throws IOException */ public void initGraphDB(String queryFile, String dbFile) throws IOException { // 读取查询子图的数据 BufferedReader q_br = new BufferedReader(new InputStreamReader( new FileInputStream(queryFile))); String lineData = q_br.readLine(); GraphBean qgb; if (lineData.startsWith("t #")) {// 第一个子图 qgb = new GraphBean(); while ((lineData = q_br.readLine()) != null) { if (lineData.startsWith("t #")) { this.query_g.add(qgb); qgb = new GraphBean(); continue; } else if (lineData.startsWith("v")) { // 顶点 String vs[] = lineData.split(" "); VertexBean vb = new VertexBean(); vb.setVertex(vs[1]); vb.setLabel(vs[2]); qgb.getvList().add(vb); } else { // 边 String es[] = lineData.split(" "); EdgeBean eb = new EdgeBean(); eb.setVertex_i(es[1]); eb.setVertex_j(es[2]); eb.setLabel_e(es[3]); qgb.geteList().add(eb); } } } // 读取图数据 BufferedReader db_br = new BufferedReader(new InputStreamReader( new FileInputStream(dbFile))); lineData = db_br.readLine(); GraphBean dbgb; if (lineData.startsWith("t #")) {// dbgb = new GraphBean(); while ((lineData = db_br.readLine()) != null) { if (lineData.startsWith("t #")) { this.mydb_g.add(dbgb); dbgb = new GraphBean(); continue; } else if (lineData.startsWith("v")) { // 顶点 String vs[] = lineData.split(" "); VertexBean vb = new VertexBean(); vb.setVertex(vs[1]); vb.setLabel(vs[2]); dbgb.getvList().add(vb); } else if (lineData.startsWith("e")) { // 边 String es[] = lineData.split(" "); EdgeBean eb = new EdgeBean(); eb.setVertex_i(es[1]); eb.setVertex_j(es[2]); eb.setLabel_e(es[3]); dbgb.geteList().add(eb); } } } } /** * 返回边的label * @param i * @param j * @param ebList * @return */ public String getLabel(String i, String j, ArrayList<EdgeBean> ebList) { for (int k = 0; k < ebList.size(); k++) { EdgeBean eb = ebList.get(k); String vi = eb.getVertex_i(); String vj = eb.getVertex_j(); if (i.equals(vi) && j.equals(vj)) return eb.getLabel_e(); else if (j.equals(vi) && i.equals(vj)) return eb.getLabel_e(); } return null; } public boolean isIsomorphism(GraphBean subgraph, GraphBean graphdb) { int M0[][] = getMatrixM(subgraph, graphdb); int MA[][] = subgraph.getMatrix(); int MB[][] = graphdb.getMatrix(); ArrayList<EdgeBean> ebq = subgraph.geteList(); ArrayList<EdgeBean> ebdb = graphdb.geteList(); // 对任意的MA[i][x] = 1 ==> 存在y M[x][y]MB[y][j] = 1 否则M0[i][j] = 0 for (int i = 0; i < subgraph.getvList().size(); i++) { for (int j = 0; j < graphdb.getvList().size(); j++) { if (M0[i][j] == 1) { String ilabel = subgraph.getvList().get(i).getLabel(); String jlabel = graphdb.getvList().get(j).getLabel(); if (ilabel.equals(jlabel)) { for (int x = 0; x < subgraph.getvList().size(); x++) { boolean tag = false; if (MA[i][x] == 1) { String label_ix = getLabel(String.valueOf(i), String.valueOf(x), ebq); for (int y = 0; y < graphdb.getvList().size(); y++) { if (M0[x][y] * MB[y][j] == 1) { String label_yj = getLabel( String.valueOf(y), String.valueOf(j), ebdb); if (label_ix.equals(label_yj)) {///比较顶点之间的边上的标签,看是否相等。 tag = true; break; } } }// break if (!tag) { M0[i][j] = 0; break; } } }// break } else {// if(ilabel.equals(jlabel)) M0[i][j] = 0; } }// if (M0[i][j] == 1) } } // System.out.println("M':"); for (int i = 0; i < subgraph.getvList().size(); i++) { int sumi = 0; for (int j = 0; j < graphdb.getvList().size(); j++) { // System.out.print(M0[i][j] + " "); sumi += M0[i][j]; } if (sumi == 0) { // System.out.println("M0有一行元素都是0"); return false; }// 有一行的元素都是0,直接退出 // System.out.println(); } int raw = subgraph.getvList().size(); int col = graphdb.getvList().size(); int F[] = new int[col];// F[i] = 1 ,表示第i列已经用过了 int H[] = new int[raw];// H[d] = k ,表示第d行选的是第k列 int d = 0;// M0的第d行 int k = 0;// M0的第k列 int[][][] matrixList = new int[raw][][];// 用来记录每次d所对应的M0 for (int i = 0; i < F.length; i++) { F[i] = -1; } for (int i = 0; i < H.length; i++) { H[i] = -1; } // ////////////////////////////// while (true) { if (H[d] == -1) { k = 0; matrixList[d] = M0; } else {// 回溯 k = H[d] + 1; F[H[d]] = -1; M0 = matrixList[d]; } while (k < col) {// 也就是M0的列 if (M0[d][k] == 1 && F[k] == -1) {// 这样的列找到后就跳出,其他的在回溯的时候再遍历 break; } k++; } if (k == col) {// 第d行中没有满足条件的列,回溯到上一层 H[d] = -1; d--; } else {// M0[d][k]=1,第d行的其他元素都为0 for (int j = 0; j < col; j++) { M0[d][j] = 0; } M0[d][k] = 1; H[d] = k; F[k] = 1; d++; } if (d == -1) { // System.out.println("不同构"); return false; } if (d == raw) {// 即找到了一个M0,接下里就是验证 if (this.isTrueFor(MA, MB, M0)) {// 条件成立 // System.out.println("同构"); return true; } else {// 回溯 d = raw - 1; } }// if }// while } /** * for all element int MA[i][j]=1 ==> MC=M*{(M*MB)^T},MC[i][j]=1 * * @param MA * @param MB * @param M * @return */ public boolean isTrueFor(int[][] MA, int[][] MB, int M[][]) { boolean flag = true; int raw = M.length; int column = MB[0].length; int tmp[][] = new int[raw][column];// tmp[][]=M*MB for (int i = 0; i < raw; i++) {// raws for (int j = 0; j < column; j++) {// columns for (int k = 0; k < M[0].length; k++) { tmp[i][j] += M[i][k] * MB[k][j]; } } } int tmp_t[][] = new int[column][raw];// 转置 for (int i = 0; i < raw; i++) {// raws for (int j = 0; j < column; j++) {// columns tmp_t[j][i] = tmp[i][j]; } } int MC[][] = new int[MA.length][MA[0].length]; // System.out.println("MC:"); for (int i = 0; i < MA.length; i++) {// raws for (int j = 0; j < MA[0].length; j++) {// columns for (int k = 0; k < M[0].length; k++) { MC[i][j] += M[i][k] * tmp_t[k][j]; } // System.out.print(MC[i][j] + " "); } // System.out.println(); } for (int i = 0; i < MA.length; i++) {// raws for (int j = 0; j < MA[0].length; j++) {// columns if (MA[i][j] == 1) { if (MC[i][j] == 1) continue; else return false; } } } return flag; } public static void main(String[] args) { IsomorphismImpl ii = new IsomorphismImpl(); String queryFile = "C:\\Users\\Fernando\\Desktop\\Q24.my"; String dbFile = "C:\\Users\\Fernando\\Desktop\\mygraphdb.data"; try { ii.initGraphDB(queryFile, dbFile); ArrayList<GraphBean> query_g = ii.getQuery_g(); System.out.println("子图(size):" + query_g.size()); ArrayList<GraphBean> db_g = ii.getMydb_g(); System.out.println("总图(size):" + db_g.size()); for (int i = 0; i < query_g.size(); i++) { for (int j = 0; j < db_g.size(); j++) { GraphBean tq = query_g.get(i); GraphBean tdb = db_g.get(j); if (ii.isIsomorphism(tq, tdb)) { System.err.println("t # " + i + " 与 T # " + j + " 同构"); } } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
package ucas.iie.graph.bean; import java.util.ArrayList; public class GraphBean { /** 图的数据格式 * t # 0 表示第0个图 v 0 2 v 1 2 v 2 2 v 3 2 v 4 2 e 0 1 2 e 1 2 2 e 2 3 2 e 3 4 2 */ private ArrayList<VertexBean> vList; private ArrayList<EdgeBean> eList; public GraphBean(){ vList = new ArrayList<VertexBean>(); eList = new ArrayList<EdgeBean>(); } public ArrayList<VertexBean> getvList() { return vList; } public void setvList(ArrayList<VertexBean> vList) { this.vList = vList; } public ArrayList<EdgeBean> geteList() { return eList; } public void seteList(ArrayList<EdgeBean> eList) { this.eList = eList; } public int[][] getMatrix(){ int[][] M = new int[vList.size()][vList.size()]; for (int index = 0; index < eList.size(); index++) { EdgeBean eb = eList.get(index); int i = Integer.parseInt(eb.getVertex_i()); int j = Integer.parseInt(eb.getVertex_j()); M[i][j] = 1; M[j][i] = 1; } // System.out.println("MA/MB:"); // for (int i = 0; i < vList.size(); i++) { // for (int j = 0; j < vList.size(); j++) { // System.out.print(M[i][j] + " "); // } // System.out.println(); // } return M; } /** * * @param v * @return 返回顶点v的度 */ public int getVDegree(String v){ int sumDeg = 0; for (int i = 0; i < eList.size(); i++) { if(eList.get(i).getVertex_i().equals(v)|| eList.get(i).getVertex_j().equals(v)){ sumDeg ++; } } return sumDeg; } public String toString(){ String res = ""; for (int i = 0; i < this.vList.size(); i++) { res +="v " + vList.get(i).getVertex() + " " + vList.get(i).getLabel() + "\r\n"; } for (int j = 0; j < this.eList.size(); j++) { res +="e " + eList.get(j).getVertex_i() + " " + eList.get(j).getVertex_j() + " "+eList.get(j).getLabel_e() + "\r\n"; } return res; } public static void main(String[] args) { new GraphBean().getMatrix(); } }
package ucas.iie.graph.bean; public class EdgeBean {//“e i j k” 表示图的边<i,j>的label是k /** 图的数据格式 * t # 0 表示第0个图 v 0 2 v 1 2 v 2 2 v 3 2 v 4 2 e 0 1 2 e 1 2 2 e 2 3 2 e 3 4 2 */ private String vertex_i; private String vertex_j; private String label_e; public String getVertex_i() { return vertex_i; } public void setVertex_i(String vertex_i) { this.vertex_i = vertex_i; } public String getVertex_j() { return vertex_j; } public void setVertex_j(String vertex_j) { this.vertex_j = vertex_j; } public String getLabel_e() { return label_e; } public void setLabel_e(String label_e) { this.label_e = label_e; } }
package ucas.iie.graph.bean; public class VertexBean { //“v i j” 表示图的顶点i的label是j /** 图的数据格式 * t # 0 表示第0个图 v 0 2 v 1 2 v 2 2 v 3 2 v 4 2 e 0 1 2 e 1 2 2 e 2 3 2 e 3 4 2 */ private String vertex; private String label; public String getVertex() { return vertex; } public void setVertex(String vertex) { this.vertex = vertex; } public String getLabel() { return label; } public void setLabel(String label) { this.label = label; } }