The following user-defined function regularify
checks if a graph is regularizable and in case gives the regularization solution.
It uses the lpSolve and lpSolveAPI packages for solving linear, integer and mixed integer programs.
In order to find a positive solution \(w > 0\), the program solves the linear problem \[\hat{B} (\hat{w}, r) = -d\] with \(\hat{w} \geq 0\), where:
- \(\hat{B}\) is the incidence matrix \(B\) with one additional column \(-e\),
- \(d\) is a vector with node degrees, and
- \((\hat{w}, r)\) is a vector with weight variables \(\hat{w}\) and an additional variable \(r\) for the regularization degree.
Setting \(w = \hat{w} + 1\), the problem corresponds to \(B w = r e\), with the constrain that \(w \geq 1\).
library(lpSolve)
library(lpSolveAPI)
regularify = function (g) {
n = vcount(g)
m = ecount(g)
B = make_incidence(g)
# objective function
obj = rep(0, m + 1)
# constraint matrix
con = cbind(B, rep(-1, n))
# direction of constraints
dir = rep("=", n)
# right hand side terms
rhs = -degree(g)
# solve the LP problem
sol = lp("max", obj, con, dir, rhs)
# get solution
if (sol$status == 0) {
s = sol$solution
# weights
w = s[1:m] + 1
# weighted degree
d = s[m+1]
}
# return the solution
if (sol$status == 0) {
return(list(weights = w, degree = d))
}
else {
return(NULL)
}
}
The following user-defined function power
computes power using a direct computation on a regularizable adjacency matrix A:
# Compute power x = (1/x) A
#INPUT
# A = graph adjacency matrix
# t = precision
# OUTPUT
# A list with:
# vector = power vector
# iter = number of iterations
power = function(A, t) {
n = dim(A)[1];
# x_2k
x0 = rep(0, n);
# x_2k+1
x1 = rep(1, n);
# x_2k+2
x2 = rep(1, n);
diff = 1
eps = 1/10^t;
iter = 0;
while (diff > eps) {
x0 = x1;
x1 = x2;
x2 = (1/x2) %*% A;
diff = sum(abs(x2 - x0));
iter = iter + 1;
}
# it holds now: alpha x2 = (1/x2) A
alpha = ((1/x2) %*% A[,1]) / x2[1];
# hence sqrt(alpha) * x2 = (1/(sqrt(alpha) * x2)) A
x2 = sqrt(alpha) %*% x2;
return(list(vector = as.vector(x2), iter = iter))
}