Jump to content

Weisfeiler Leman graph isomorphism test

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Tpreu (talk | contribs) at 00:05, 29 October 2023 (I stop here for the moment, examples will be developed, the remaining sections fleshed out.). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

In graph theory, the Weisfeiler Leman graph isomorphism test is a heuristic test for the existence of an isomorphism between two graphs G and H.[1] It is based on a normal form for graphs first described in an article by Weisfeiler and Leman in 1968.[2] There are several versions of the test, these versions are referred in the literature by various names, which easily leads to confusion.

The basic Weisfeiler Leman graph isomorphism test

The basic version called WLtest takes a graph as input, produces a partition of the nodes which is invariant under automorphisms and outputs a string certificate encoding the partition. When applied to two graphs G and H we can compare the certificates. If the certificates do not agree the test fails and G and H cannot be isomorphic. If the certificates agree, G and H may or may not be isomorphic.

The partition is produced in several rounds starting from the trivial partition where all nodes belong to the same component. In each round the partition is refined, which means that once two nodes are in different components they will also be in different components at future rounds. The partition refinement stops when the partition from the last round and the current partition are the same. This means that the refinement stops after rounds where n is the number of nodes in the graph. This is because the number of components need to grow by at least 1 in each step and the number of components cannot exceed n.

Membership of a node in a component is indicated by a label. In each round labels are recomputed and refined. After termination of the refinement, stringing together the labels after sorting yields the certificate. In order for isomorphic graphs to produce the same certificate one has to be very cautious with the labels because an isomorphism may swap nodes and may modify the order in which nodes are processed which in turn may alter the certificate. As an example the labels in the end may be 2-fold x, a single y and 2-fold z for one graph and a single x, 2-fold y and 2-fold z for an isomorphic graph yielding after sorting and stringing x_x_y_z_z resp. x_y_y_z_z.

One can be less careful with the labels, if one applies WLtest to a single graph created as the disjoint union of the two graphs G and H. Applying to the disjoint union will ensure that both graphs are processed in parallel at each stage, which will avoid such a swap of labels, say x and y as in the example above. Additionally the parallel processing can distinguish even more pairs of non-isomorphic graphs, see the examples below. In what follows we will discuss this version WLpairs.

The refinement of the partition in each step is by processing for each node its label and the labels of its nearest neighbors. Therefore WLtest can be viewed as a message passing algorithm.

#ALGORITHM WLpairs
#INPUT: two graphs G and H to be tested for isomorphism
#OUTPUT: Certificates for G and H and whether they agree
U = combineTwo(G,H)
glabels = initializeLabels(U) #dictionary where every node gets the same label 0
labels = {} #dictionary that will provide translation from a string of labels of a node and its neighbors to an integer
newLabel = 1
done = False
while not(done):
  glabelsNew = {} #set up the dictionary of labels for the next step
  for node in U:
    label = str(glabels[node]) + str([glabels[x] for x in neighbors of node].sort())
    if not(label in labels): #a combination of labels from the node and its neighbors is encountered for the first time
      labels[label] = newLabel #assign the string of labels to a new number as an abbreviated label
      newLabel += 1 #increase the counter for assigning new abbreviated labels
    glabelsNew[node] = labels[lebel]
  if (number of different labels in glabels) == (number of different labels in glabelsNew):
    done = True
  else:
    glabels = glabelsNew.copy()
certificateG = certificate for G from the sorted labels of the G-part of U
certificateH = certificate for H from the sorted labels of the H-part of U
if certificateG == certificateH:
  test=True
else:
  test=False

Here is some actual python code which includes the description of the first examples.

g5_00={0:{1,2,4}, 1:{0,2}, 2:{0,1,3}, 3:{2,4}, 4:{0,3}}
g5_01={0:{3,4}, 1:{2,3,4}, 2:{1,3}, 3:{0,1,2}, 4:{0,1}}
g5_02={0:{1,2,4}, 1:{0,3}, 2:{0,3}, 3:{1,2,4}, 4:{0,3}}

def combineTwo(g1,g2):
  g={}
  n=len(g1)
  for node in g1:
    s=set()
    for neighbor in g1[node]:
      s.add(neighbor)
    g[node]=s.copy()
  for node in g2:
    s=set()
    for neighbor in g2[node]:
      s.add(neighbor+n)
    g[node+n]=s.copy()
  return g

g=combineTwo(g5_00,g5_02)
labels={}
glabels={}
for i in range(len(g)):
  glabels[i]=0
glabelsCount=1
newlabel=1

done=False
while not(done):
  glabelsNew={}
  glabelsCountNew=0
  for node in g:
    label=str(glabels[node])
    s2=[]
    for neighbor in g[node]:
      s2.append(glabels[neighbor])
    s2.sort()
    for i in range(len(s2)):
      label+="_"+str(s2[i])
    if not (label in labels):
      labels[label]=newlabel
      newlabel+=1
      glabelsCountNew+=1
    glabelsNew[node]=labels[label]
  if glabelsCount==glabelsCountNew:
    done=True
  else:
    glabelsCount=glabelsCountNew
    glabels=glabelsNew.copy()
print(glabels)

g0labels=[]
for i in range(len(g0)):
  g0labels.append(glabels[i])
g0labels.sort()
certificate0=""
for i in range(len(g0)):
  certificate0+=str(g0labels[i])+"_"
g1labels=[]
for i in range(len(g1)):
  g1labels.append(glabels[i+len(g0)])
g1labels.sort()
certificate1=""
for i in range(len(g1)):
  certificate1+=str(g1labels[i])+"_"

if certificate0==certificate1:
  test=True
else:
  test=False
print("Certificate 0:",certificate0)
print("Certificate 1:",certificate1)
print("Test yields:",test)

Examples

Graph G0 Graph G1 Graph G2

Graph G0 to demonstrate the Weisfeiler Leman test.

Graph G1 to demonstrate the Weisfeiler Leman test.

Graph G2 to demonstrate the Weisfeiler Leman test.


Applications

The theory behind the Weisfeiler Leman test is applied in graph neural networks.

See also

References

  1. ^ Huang, Ningyuan; Villar, Soledad (2022), "A Short Tutorial on the Weisfeiler-Lehman Test and Its Variants", ICASSP 2021 - 2021 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP), pp. 8533–8537, arXiv:2201.07083, doi:10.1109/ICASSP39728.2021.9413523, ISBN 978-1-7281-7605-5, S2CID 235780517
  2. ^ Weisfeiler, B. Yu.; Leman, A. A. (1968). "A Reduction of a Graph to a Canonical Form and an Algebra Arising during This Reduction" (PDF). Nauchno-Technicheskaya Informatsia. 2 (9): 12–16. Retrieved 2023-10-28.