Reputation: 73
Given an array of values:
x = array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
I would like to know if there is an optimal way to easily obtain its equivalent adjacency matrix:
M = array([[ inf, 1., inf, 3., 4., inf, inf, inf, inf],
[ 0., inf, 2., 3., 4., 5., inf, inf, inf],
[ inf, 1., inf, inf, 4., 5., inf, inf, inf],
[ 0., 1., inf, inf, 4., inf, 6., 7., inf],
[ 0., 1., 2., 3., inf, 5., 6., 7., 8.],
[ inf, 1., 2., inf, 4., inf, inf, 7., 8.],
[ inf, inf, inf, 3., 4., inf, inf, 7., inf],
[ inf, inf, inf, 3., 4., 5., 6., inf, 8.],
[ inf, inf, inf, inf, 4., 5., inf, 7., inf]])
The idea really is to build an object in networx with which to work, and I am looking to obtain the adjacency matrix of a cell grid to be able to load that matrix in networkx, but if there is a better way to achieve it I am open to suggestions. According to documentation I have been able to find the grid_2d_graph () function that allows dimensioning the graph that I want given the n rows and m columns of the original matrix, however I want the weight to go from one node to another (if possible), be the value of the array that the target node occupies.
EDIT
Although the proposed example is a particular case (square matrix and ordered values), the problem arises for any matrix, with dimensions not necessarily equal and random values.
Upvotes: 1
Views: 1171
Reputation: 3283
I think this is what you're after:
def create_adj_mat(x):
y = np.ones([x.size,np.max(x)+1]) * np.inf #initialize
for I,i in enumerate(np.ravel(x)):
#get adjacent values of y and x points
d = x[max(0,I//x.shape[1]-1):min(x.shape[0],I//x.shape[1]+2),
max(0,I%x.shape[1]-1):min(x.shape[1],I%x.shape[1]+2)]
y[I,np.ravel(d)] = np.ravel(d)
np.fill_diagonal(y,np.inf) #remove i,i points
return y
It iterates through the ravelled values of your input matrix and finds the adjacent values (-1 and +2 offset, +2 because of python indexing) and sets the array y according to these values.
When you pass your matrix, you get:
x = np.array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
y = create_adj_mat(x)
print(y)
array([[inf, 1., inf, 3., 4., inf, inf, inf, inf],
[ 0., inf, 2., 3., 4., 5., inf, inf, inf],
[inf, 1., inf, inf, 4., 5., inf, inf, inf],
[ 0., 1., inf, inf, 4., inf, 6., 7., inf],
[ 0., 1., 2., 3., inf, 5., 6., 7., 8.],
[inf, 1., 2., inf, 4., inf, inf, 7., 8.],
[inf, inf, inf, 3., 4., inf, inf, 7., inf],
[inf, inf, inf, 3., 4., 5., 6., inf, 8.],
[inf, inf, inf, inf, 4., 5., inf, 7., inf]])
EDIT
Assuming the representation of a non-ordered, non-square matrix, I've made a minor change to my code to look like this:
def create_adj_mat(x):
y = np.ones([np.max(x)+1,np.max(x)+1]) * np.inf #initialize
for I,i in enumerate(np.ravel(x)):
#get adjacent values of y and x points
d = x[max(0,I//x.shape[1]-1):min(x.shape[0],I//x.shape[1]+2),
max(0,I%x.shape[1]-1):min(x.shape[1],I%x.shape[1]+2)]
y[i,np.ravel(d)] = np.ravel(d)
np.fill_diagonal(y,np.inf) #remove i,i points
return y
Then, when you pass such an array:
d = np.array([[10,3],[5,12],[2,1]])
create_adj_mat(d)
array([[inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf],
[inf, inf, 2., inf, inf, 5., inf, inf, inf, inf, inf, inf, 12.],
[inf, 1., inf, inf, inf, 5., inf, inf, inf, inf, inf, inf, 12.],
[inf, inf, inf, inf, inf, 5., inf, inf, inf, inf, 10., inf, 12.],
[inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf],
[inf, 1., 2., 3., inf, inf, inf, inf, inf, inf, 10., inf, 12.],
[inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf],
[inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf],
[inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf],
[inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf],
[inf, inf, inf, 3., inf, 5., inf, inf, inf, inf, inf, inf, 12.],
[inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf],
[inf, 1., 2., 3., inf, 5., inf, inf, inf, inf, 10., inf, inf]])
Upvotes: 1
Reputation: 1888
Using networkx
to construct the implied network from the array, we
specify the weight of each di-graph edge to be the node number of the
target node. Then, we can use the adj_matrix() function to generate
the matrix:
import networkx as nx
import numpy as np
x = np.arange(9).reshape(3, 3)
G = nx.DiGraph()
# Ensure nodes sort order
G.add_nodes_from(np.arange(9))
i1, j1 = x.shape
for i in range(i1):
for j in range(j1):
if i < i1-1:
G.add_edge(x[i,j], x[i+1,j], weight=x[i+1,j])
G.add_edge(x[i+1,j], x[i,j], weight=x[i,j])
if j > 0:
G.add_edge(x[i,j], x[i+1,j-1], weight=x[i+1,j-1])
G.add_edge(x[i+1,j-1], x[i,j], weight=x[i,j])
if j < j1-1:
G.add_edge(x[i,j], x[i,j+1], weight=x[i,j+1])
G.add_edge(x[i,j+1], x[i,j], weight=x[i,j])
if i < i1-1:
G.add_edge(x[i,j], x[i+1,j+1], weight=x[i+1,j+1])
G.add_edge(x[i+1,j+1], x[i,j], weight=x[i,j])
if i > 0:
G.add_edge(x[i,j], x[i-1,j+1], weight=x[i-1,j+1])
G.add_edge(x[i-1,j+1], x[i,j], weight=x[i,j])
am1 = nx.adj_matrix(G).todense().astype(float)
np.putmask(am1, am1==0, np.inf)
print(am1)
Output:
# [[inf 1. inf 3. 4. inf inf inf inf]
# [inf inf 2. 3. 4. 5. inf inf inf]
# [inf 1. inf inf 4. 5. inf inf inf]
# [inf 1. inf inf 4. inf 6. 7. inf]
# [inf 1. 2. 3. inf 5. 6. 7. 8.]
# [inf 1. 2. inf 4. inf inf 7. 8.]
# [inf inf inf 3. 4. inf inf 7. inf]
# [inf inf inf 3. 4. 5. 6. inf 8.]
# [inf inf inf inf 4. 5. inf 7. inf]]
Upvotes: 0