子图同构算法Ullmann实现,并采取了Refinement(java语言)

子图同构算法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;
	}

}
时间: 2024-10-30 21:21:38

子图同构算法Ullmann实现,并采取了Refinement(java语言)的相关文章

子图同构算法系列(1)

取自 1976 Ullmann Part2 Naive alogrithm for Subgraph Isomorphism. 1. 如何判定子图同构. 有个Gα和Gβ, Gα有pa个点,qa条边,Gβ有pb个点,qb条边.A是Gα的邻接矩阵,相应的B是Gβ的邻接矩阵.那么如何判断同构呢.设A是子图,B是原图.那么有一个A的点到B的点的映射.这个映射的模式叫做M.M是pa行,pb列的.M有一个性质就是每行只有一个1,每列至多一个1.这个就是一个A中的点到B中的点的一个映射.我们定义一个C = [

静态频繁子图挖掘算法用于动态网络——gSpan算法研究

摘要 随着信息技术的不断发展,人类可以很容易地收集和储存大量的数据,然而,如何在海量的数据中提取对用户有用的信息逐渐地成为巨大挑战.为了应对这种挑战,数据挖掘技术应运而生,成为了最近一段时期数据科学的和人工智能领域内的研究热点.数据集中的频繁模式作为一种有价值的信息,受到了人们的广泛关注,成为了数据挖掘技术研究领域内的热门话题和研究重点. 传统的频繁模式挖掘技术被用来在事务数据集中发现频繁项集,然而随着数据挖掘技术应用到非传统领域,单纯的事务数据结构很难对新的领域的数据进行有效的建模.因此,频繁

子图同构

子图同构定义: 给定图$Q=(V(Q),E(Q),L_V,F)$和$G=(V(G),E(G),L_V',F')$,  称$Q$子图同构于$G$ 当且仅当存在一个映射$g:V(Q)\rightarrow V(G)$ 使得 \[\forall x\in V(Q), F(v)=F'(g(v))\] 和 \[\forall v_1 ,v_2 \in V(Q),\overrightarrow {v_1 v_2 } \in E(Q) \Rightarrow \overrightarrow {g(v_1 )g

gSpan频繁子图挖掘算法

参考资料:http://www.cs.ucsb.edu/~xyan/papers/gSpan.pdf http://www.cs.ucsb.edu/~xyan/papers/gSpan-short.pdf http://www.jos.org.cn/1000-9825/18/2469.pdf http://blog.csdn.net/coolypf/article/details/8263176 更多挖掘算法:https://github.com/linyiqun/DataMiningAlgor

算法笔记_216:第六届蓝桥杯软件类校赛部分真题(Java语言C组)

目录 1 题目一 2 题目二 3 题目三 4 题目四 5 题目五 前言:以下代码仅供参考,若有错误欢迎指正哦~ 1 题目一 二项式的系数规律,我国数学家很早就发现了. 如[图1.png],我国南宋数学家杨辉1261年所著的<详解九章算法>一书里就出现了. 其排列规律: 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 35 35 21 7 1 如下的程序,用来建立N行的杨辉三角形.请填写划线部分缺少的代码.

算法之求质数(Java语言)

质数(Prime number) 又称素数,指在大于1的自然数中,除了1和该数自身外,无法被其他自然数整除的数(也可定义为只有1与该数本身两个因数的数). 算法原理 验证一个数字 n 是否为素数的一种简单但缓慢的方法为试除法.此一方法会测试 n 是否为任一在2与之间的整数之倍数. 实现示例(Java语言) 1 public class PrimeNumberExample { 2 3 public static boolean isPrime(long n) { 4 5 if(n > 2 &

LeetCode算法题-Number of 1 Bits(Java实现)

这是悦乐书的第186次更新,第188篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第45题(顺位题号是191).编写一个带无符号整数的函数,并返回它所具有的"1"位数.例如: 输入:11 输出:3 说明:整数11具有二进制表示00000000000000000000000000001011 输入:128 输出:1 说明:整数128具有二进制表示00000000000000000000000010000000 本次解题使用的开发工具是eclipse,jdk使

LeetCode算法题-Remove Linked List Elements(Java实现)

这是悦乐书的第189次更新,第191篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第48题(顺位题号是203).移除单链表中节点值为val的节点.例如: 输入:1-> 2-> 6-> 3-> 4-> 5-> 6,val = 6 输出:1-> 2-> 3-> 4-> 5 本次解题使用的开发工具是eclipse,jdk使用的版本是1.8,环境是win7 64位系统,使用Java语言编写和测试. 02 第一种解法 特殊情况

LeetCode算法题-Next Greater Element I(Java实现)

这是悦乐书的第244次更新,第257篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第111题(顺位题号是496).你有两个数组(没有重复)nums1和nums2,其中nums1的元素是nums2的子集.在nums2的相应位置找到nums1元素的所有下一个更大的数字.nums1中的数字x的下一个更大数字是nums2中右边第一个更大的数字.如果它不存在,则输出该数字的-1.例如: 输入:nums1 = [4,1,2],nums2 = [1,3,4,2]. 输出:[-1,