Graphs are typically represented as adjacency lists. But if they're represented as matrices, you get all the juicy goodness of linear algebra.

What does this mean? Well, for example, let's represent this directed graph as a matrix.

Digraph from Segewick's "Algorithms". |

The same digraph. |

A

_{i,j}is 1 when i is linked to j and 0 otherwise. Since there are no self-loops, A

_{i,i}= 0.

In Python, it would look like this:

import numpy as np

from numpy.linalg import eig

from scipy.linalg import lu

import networkx as nx

import sympy

A = np.matrix( # 0 1 2 3 4 5 6 7 8 9 10 11 12

'0 1 0 0 0 1 1 0 0 0 0 0 0;' # 0

'0 0 0 0 0 0 0 0 0 0 0 0 0;' # 1

'1 0 0 1 0 0 0 0 0 0 0 0 0;' # 2

'0 0 0 0 0 1 0 0 0 0 0 0 0;' # 3

'0 0 0 0 0 0 0 0 0 0 0 0 0;' # 4

'0 0 0 0 1 0 0 0 0 0 0 0 0;' # 5

'0 0 0 0 1 0 0 0 0 1 0 0 0;' # 6

'0 0 0 0 0 0 1 0 0 0 0 0 0;' # 7

'0 0 0 0 0 0 0 1 0 0 0 0 0;' # 8

'0 0 0 0 0 0 0 0 0 0 1 1 1;' # 9

'0 0 0 0 0 0 0 0 0 0 0 0 0;' # 10

'0 0 0 0 0 0 0 0 0 0 0 0 1;' # 11

'0 0 0 0 0 0 0 0 0 0 0 0 0' # 12

)

It's worth noting that the eigenvalues of this matrix are all 0:

print "eigenvalues = ", eig(A)[0] # [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

This is always true of adjacency matrices that are acyclic. I'll explain why.

Firstly, if we re-label the nodes, we can change the order of the rows and columns such that it becomes an upper triangular matrix. Given an order that I calculated elsewhere:

newOrder = [2, 0, 1, 3, 5, 8, 7, 6, 4, 9, 10, 11, 12]

re_arranged_cols = A[newOrder, :]

re_arranged_rows_and_cols = re_arranged_cols[:, newOrder]

we get a matrix that looks like this:

[[0 1 0 1 0 0 0 0 0 0 0 0 0]

[0 0 1 0 1 0 0 1 0 0 0 0 0]

[0 0 0 0 0 0 0 0 0 0 0 0 0]

[0 0 0 0 1 0 0 0 0 0 0 0 0]

[0 0 0 0 0 0 0 0 1 0 0 0 0]

[0 0 0 0 0 0 1 0 0 0 0 0 0]

[0 0 0 0 0 0 0 1 0 0 0 0 0]

[0 0 0 0 0 0 0 0 1 1 0 0 0]

[0 0 0 0 0 0 0 0 0 0 0 0 0]

[0 0 0 0 0 0 0 0 0 0 1 1 1]

[0 0 0 0 0 0 0 0 0 0 0 0 0]

[0 0 0 0 0 0 0 0 0 0 0 0 1]

[0 0 0 0 0 0 0 0 0 0 0 0 0]]

which also has all zero eigenvalues:

print "eigenvalues for this new matrix: ", eig(re_arranged_rows_and_cols)[0]<-- all="" as="" expected="" font="" zeroes="">

Notice that with this new choice of basis, the matrix has all the connections (that is, the 1 values) above the diagonal and the diagonal values themselves are all zeros (since even with this re-ordering there are still no self-loops).

__Triangular Matrices__
Now, an interesting thing about upper triangular matrices is that their diagonals are their eigenvalues. The reason for this follows this recipe:

1. The elements in an upper triangular matrix, a

2. A formula for calculating the determinants is this one from Leibniz:

where

Take a look at the rightmost element of (2). It multiplies n elements of the matrix given by a

that is, the determinant is the product of the diagonals.

Given that you calculate the eigenvalues from the characteristic equation:

det(A - λ I) = 0

(where I is the identity matrix) then the eigenvalues are given by:

(λ - a

1. The elements in an upper triangular matrix, a

_{ij}are necessarily 0 if i < j (where i and j are the row and column indexes). That is:
a

_{ij}= 0 ∀ {i, j | i < j }2. A formula for calculating the determinants is this one from Leibniz:

n | ||||

det(A) = | Σ | sgn(σ) | Π | a_{σ(i),i} |

σ ∈ S _{n} | i = 1 |

where

- n is the order of the square matrix (2 if it's 2x2; 3 if it's 3x3 ...)
- σ is a permutation of n integers in the permutation group S
_{n}. - sgn(σ) is 1 or -1 depending on the order of σ. Ignore this. It will disappear.
- and σ(i) is the i-th integer in σ.

Take a look at the rightmost element of (2). It multiplies n elements of the matrix given by a

_{xi}. But remember from (1) that the product is 0 is any i is less than x. If you think about it, there is only one permutation for which this is not true, namely [1, 2, 3, ... n]. So, for a triangular matrix,n | ||||

det(A) = | Π | a_{i,i} | ||

i = 1 |

that is, the determinant is the product of the diagonals.

Given that you calculate the eigenvalues from the characteristic equation:

det(A - λ I) = 0

(where I is the identity matrix) then the eigenvalues are given by:

(λ - a

_{1,1}) . (λ - a_{2,2}) . (λ - a_{3,3}) ... (λ - a_{n,n}) = 0
The only way for this equation to hold for all eigenvalues, λ, is that each eigenvalue must equal its corresponding diagonal element. Since the diagonals of a triangular matrix representing an acyclic graph are all 0, all its eigenvalues are 0.

__Conclusion__

We've shown that just by looking at the adjacency matrix (and not tediously exploring the graph) we can tell whether the graph is cyclic or acyclic. This is done by calculating the eigenvalues which is simple given any decent maths library.

## No comments:

## Post a Comment