cal_mark <- function(x,y){
1 - abs(x - y) / max(abs(x), abs(y))
}
#' @title Percolation Graph Matching Methods
#' @rdname gm_perco
#'
#' @return \code{graph_match_percolation} returns an object of class "\code{\link{graphMatch}}" which is a
#' list containing the following components:
#'
#' \describe{
#' \item{corr_A}{matching correspondence in \eqn{G_1}}
#' \item{corr_B}{matching correspondence in \eqn{G_2}}
#' \item{match_order}{the order of vertices getting matched}
#' \item{seeds}{a vector of logicals indicating if the corresponding vertex is a seed}
#' }
#'
#'
#'
#'
#' @param A A matrix, igraph object, or list of either.
#' @param B A matrix, igraph object, or list of either.
#' @param seeds A vector of integers or logicals, a matrix or a data frame. If
#' the seed pairs have the same indices in both graphs then seeds can be a
#' vector. If not, seeds must be a matrix
#' or a data frame, with the first column being the indices of \eqn{G_1} and
#' the second column being the corresponding indices of \eqn{G_2}.
#' @param similarity A matrix. An \code{n-by-n} matrix containing vertex similarities.
#' @param r A number. Threshold of neighboring pair scores.
#' @param ExpandWhenStuck A logical. TRUE if expand the seed set when Percolation algorithm
#' stops before matching all the vertices.
#'
#' @references L. Yartseva and M. Grossglauser (2013), \emph{On the performance
#' of percolation graph matching}. COSN, Boston, MA, USA, pages 119–130.
#' @references E. Kazemi, S. H. Hassani, and M. Grossglauser (2015),
#' \emph{Growing a graph matching from a handful of seeds}. Proc. of the VLDB
#' Endowment, 8(10):1010–1021.
#'
#' @examples
#' # match G_1 & G_2 using percolation graph matching method
#' cgnp_pair <- sample_correlated_gnp_pair(n = 20, corr = 0.5, p = 0.8)
#' g1 <- cgnp_pair$graph1
#' g2 <- cgnp_pair$graph2
#' seeds <- 1:10 <= 3
#' GM_perco <- gm(g1, g2, seeds, method = "percolation", r = 2, ExpandWhenStuck = FALSE)
#' GM_perco
#'
#' # matching accuracy with the true alignment being the identity
#' mean(GM_perco$corr_A == GM_perco$corr_B)
#' GM_perco$match_order
#'
#' summary(GM_perco, g1, g2, true_label = 1:20)
#' plot(g1[], g2[], GM_perco)
#'
#' # expand when stuck
#' GM_exp <- gm(g1, g2, seeds, method = "percolation", r = 4, ExpandWhenStuck = TRUE)
#' GM_exp
#'
#'
#' @keywords internal
graph_match_percolation <- function (A, B, seeds,
similarity = NULL, r = 2,
ExpandWhenStuck = FALSE) {
totv1 <- nrow(A[[1]])
totv2 <- nrow(B[[1]])
n <- max(totv1, totv2)
ns <- nrow(seeds)
nn <- n - ns
nc <- length(A)
nonseeds <- check_seeds(seeds, n)$nonseeds
seeds_ori <- seeds
Z <- seeds #matched nodes
M <- Matrix(0, n, n) #marks matrix
if(sum(abs(similarity)) != 0){
M[nonseeds$A, nonseeds$B] <- similarity
}
if(nrow(seeds_ori) != 0){
M[seeds_ori$A,] <- -n * n
M[,seeds_ori$B] <- -n * n
}
iter <- 1
while(ns != 0 | (sum(abs(similarity)) != 0 & iter == 1)){
# mark neighbors
if(ns != 0){
for(ch in 1:nc){
directed <- !(isSymmetric(A[[ch]]) && isSymmetric(B[[ch]]))
for(i in 1:nrow(seeds)){
A_adj <- which(A[[ch]][seeds$A[i],]!=0)
B_adj <- which(B[[ch]][seeds$B[i],]!=0)
if(length(A_adj) != 0 && length(B_adj) != 0){
mark <- outer(A[[ch]][seeds$A[i],A_adj], B[[ch]][seeds$B[i], B_adj], cal_mark)
M[A_adj, B_adj] <- M[A_adj, B_adj] + mark
}
if(directed){
A[[ch]] <- Matrix::t(A[[ch]])
B[[ch]] <- Matrix::t(B[[ch]])
A_adj <- which(A[[ch]][seeds$A[i],]!=0)
B_adj <- which(B[[ch]][seeds$B[i],]!=0)
if(length(A_adj) != 0 && length(B_adj) != 0){
mark <- outer(A[[ch]][seeds$A[i],A_adj], B[[ch]][seeds$B[i], B_adj], cal_mark)
M[A_adj, B_adj] <- M[A_adj, B_adj] + mark
}
A[[ch]] <- Matrix::t(A[[ch]])
B[[ch]] <- Matrix::t(B[[ch]])
}
}
}
}
# choose pairs with marks ge r
while(max(M) >= r){
max_ind <- Matrix::which(M == max(M), arr.ind = TRUE)
if(nrow(max_ind) != 1){
degree_diff <- 0
for (ch in 1:nc) {
degree_diff <- degree_diff + abs(rowSums(A[[ch]])[max_ind[,1]]-rowSums(B[[ch]])[max_ind[,2]])
}
max_ind <- max_ind[which(degree_diff == min(degree_diff)),]
if(is.vector(max_ind) == FALSE){
max_ind <- max_ind[sample(nrow(max_ind),1),]
}
}
# update mark matrix
for( ch in 1:nc ){
directed <- !(isSymmetric(A[[ch]]) && isSymmetric(B[[ch]]))
A_adj <- which(A[[ch]][max_ind[1],]!=0)
B_adj <- which(B[[ch]][max_ind[2],]!=0)
if(length(A_adj) != 0 && length(B_adj) != 0){
mark <- outer(A[[ch]][max_ind[1],A_adj], B[[ch]][max_ind[2],B_adj], cal_mark)
M[A_adj, B_adj] <- M[A_adj, B_adj] + mark
}
if(directed){
A[[ch]] <- Matrix::t(A[[ch]])
B[[ch]] <- Matrix::t(B[[ch]])
A_adj <- which(A[[ch]][max_ind[1],]!=0)
B_adj <- which(B[[ch]][max_ind[2],]!=0)
if(length(A_adj) != 0 && length(B_adj) != 0){
mark <- outer(A[[ch]][max_ind[1],A_adj], B[[ch]][max_ind[2],B_adj], cal_mark)
M[A_adj, B_adj] <- M[A_adj, B_adj] + mark
}
A[[ch]] <- Matrix::t(A[[ch]])
B[[ch]] <- Matrix::t(B[[ch]])
}
}
M[max_ind[1],] <- -n * n
M[,max_ind[2]] <- -n * n
max_ind <- data.frame(A = max_ind[1], B = max_ind[2])
Z <- rbind(Z, max_ind)
}
# deferred percolation gm
iter <- iter + 1
ns <- 0
if(ExpandWhenStuck){
seeds_old <- seeds
seeds <- which(M > 0 & M < r, arr.ind = TRUE)
seeds <- data.frame(A = seeds[,1], B = seeds[,2])
ns <- nrow(seeds)
if( (nrow(seeds) == nrow(seeds_old)) && (sum(seeds == seeds_old) == 2*nrow(seeds))){
break
}
}
}
# matching result
order <- order(Z[,1])
corr <- Z[order,]
names(corr) <- c("corr_A","corr_B")
rownames(corr) <- paste0(as.character(1:nrow(corr)))
cl <- match.call()
graphMatch(
corr = corr,
nnodes = c(totv1, totv2),
call = cl,
detail = list(
match_order = order,
seeds = seeds_ori
)
)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.