# Isomorphism identification of Graphs

Given two adjacency matrices, judge three necessary and insufficient conditions:
① Same number of nodes
② Same variable
③ The number of nodes with the same degree is the same
Carry out matrix transformation on the premise of ①, ② and ③ to see whether one of the given two matrices can be transformed into another matrix;

Implementation code and Description:

```#include<iostream>
#include<stdlib.h>
#define MAX 100
using namespace std;

int points;             //Number of vertices of adjacency matrix (i.e. matrix order)
int edges;              //Number of edges of adjacency matrix (i.e. number of non zeros of adjacency matrix / 2)
int Matrix[MAX][MAX];   //matrix
int weight[MAX];        //A collection of rows and degrees
};

AdjacencyMatrix A,B;//Define adjacency matrices A and B, adjust a to B and meet the necessary conditions of isomorphism, then a and B are isomorphic
//Three necessary conditions: ① the number of nodes is the same ② the number of sides is the same ③ the number of nodes with the same degree is the same

// (exchange rows)
//The row position exchange function returns true for normal exchange. The row column exchange here is for figure A
bool SwapRows(int i,int j){
int k;
//Row exchange
for(k=0;k<A.points;k++){//Exchange rows i and j of the matrix
int temp;
temp = A.Matrix[i][k];
A.Matrix[i][k]= A.Matrix[j][k];
A.Matrix[j][k]= temp;
}
int temp;
//OK, the degree should also be exchanged
//This operation is equivalent to moving the point to a certain position,
//It is equivalent to the direct dragging of the three-dimensional world, that is, his points are stacked (or in improper order), and then we spread (or move) his points and place them again according to some rules (this rule makes the structure (matrix) of the current graph close to the target graph)
//Remember to change the degree after line exchange
temp =A.weight[i];
A.weight[i]= A.weight[j];
A.weight[j]= temp;
return true;
}

//(column exchange)

//The column position exchange function returns true for normal exchange and false for unable exchange
bool  SwapColumns(int currentLayer,int i,int j){//Why three parameters: in order to keep the previously modified trend unchanged
int k;
//Judge whether it can be exchanged

//The meaning of this loop is that I started from the first line, and our figure A should be the same as figure B. then, currentLayer is the current level
//It can be understood that it is synchronized to the current level. Then, if our columns are exchanged, if they are different, it will destroy the trend that we try to be close to the structure of figure B. we can't let it continue
//Because if we synchronize the first row in Figure A and figure B, and then figure a synchronizes with other rows in Figure B, we find that if the exchange result will affect the previous synchronization result
//So there's no isomorphism, that is, the two matrices can't be the same
for(k=0;k<currentLayer;k++){//Exchange columns i and j

if(A.Matrix[k][i]!=A.Matrix[k][j]){
//Cannot exchange, because exchange will affect the result of previous adjustment, so it is not identical.
return false;
}
}
//Perform column exchange
for(k=0;k<A.points;k++){
int temp;
temp =A.Matrix[k][i];
A.Matrix[k][i]= A.Matrix[k][j];
A.Matrix[k][j]= temp;
}
return true;
}

//Comparison algorithm for quick sorting
int cmp( const void *a , const void *b ){
return *(int *)a - *(int *)b;
}

int main(){
cout<<"Please enter the degree (number of vertices) of the two graphs:"<<endl;
cin>>A.points>>B.points;

//Judge the first necessary condition

if(A.points!=B.points){
cout<<"Different order! Different structures!"<<endl;
return 0;
}

cout<<"Please enter the adjacency matrix of the first graph:"<<endl;
A.edges = 0;
B.edges = 0;

//Input A and B matrices by adjacency matrix
int i,j,k,y;
for(i=0;i<A.points;i++){
for(j=0;j<A.points;j++){
cin>>A.Matrix[i][j];
if(A.Matrix[i][j]==1){
A.edges++;
}
}
}

cout<<"Please enter the adjacency matrix of the second graph:"<<endl;
for(i=0;i<B.points;i++){
for(j=0;j<B.points;j++){
cin>>B.Matrix[i][j];
if(B.Matrix[i][j]==1){
B.edges++;
}
}
}

//Judge the second necessary condition

if(A.edges!=B.edges){
cout<<"The number of edges is different! Different structures!"<<endl;
return 0;
}

//Because it is an adjacency matrix, the number of edges (i.e. the number of non zeros of the adjacency matrix / 2)
//When assigning values to edges, we give edges + 1 when the value of the two-dimensional matrix is 1. Because it is an undirected graph, G[i][j] and G[j][i] are the same, so we need / 2
A.edges =A.edges/2;
B.edges =B.edges/2;
int Aweight[MAX];//MAX==100
int Bweight[MAX];

//Judge the third necessary condition
int x=0;
for(k=0;k<A.points;k++){//There are point points in figure A, and then the degrees of these points are calculated
int count=0;//Initialization degree is 0
for(y=0;y<A.points;y++){
if(A.Matrix[k][y]==1){ //There are edges, degree + 1. It is unnecessary to consider / 2 here, because it is for the current point K. A.Matrix[k][y]==1 means that K has edges for the Y point (change point)
count++;//Degree + 1
}
}
Aweight[x]= count;//After traversing the statistical degree, record it in a one-dimensional array
A.weight[x++]=count;//Of course, you need to record the current degree in the weight array in the A data structure, and then x+1;

}
qsort(Aweight,A.points,sizeof(Aweight),cmp);
//Call system quick sort algorithm
//The meaning of sorting is: because the degree of the first point is uncertain, we can sort the array from small to large (or from large to small). After sorting, the array is regular
//Then, sort the array of recording point degrees in Figure B from small to large (or from large to small). After sorting, see whether it meets the following requirements:
//The third of the three necessary conditions of isomorphic graphs: the same number of nodes with the same degree

x=0;
//Do the same for matrix B
for(k=0;k<B.points;k++){
int count=0;
for(y=0;y<B.points;y++){
if(B.Matrix[k][y]==1){
count++;
}
}
Bweight[x]= count;
B.weight[x++]=count;
}
qsort(Bweight,B.points,sizeof(Bweight),cmp);//Call system quick sort algorithm
//Determine whether the third condition is met
for(k=0;k<A.points;k++){
if(Aweight[k]!=Bweight[k]){
cout<<"The degree of the edge is different! Different structures!"<<endl;
return 0;
}
}

//Perform matrix transformation

//If the three conditions are met, the final verification operation is carried out: transform the matrix of the first graph to make its structure close to the second graph
//Moreover, if the operation process is not interrupted due to the wrong judgment of the row column exchange operation (that is, the row column exchange cannot be changed into the second graph, and then it is interrupted)

//Adjust matrix A to matrix B. please note that the following operations column exchange must be accompanied by row exchange. Why: because although there is not much correlation between the rows and columns of the matrix, even if row exchange and column exchange do not change the mapping relationship between their points
//Nor does it say that columns must be exchanged after rows are exchanged, but in the matrix representing the graph, the order of points is meaningful;
for(i=0;i<B.points;i++){
for(j=i;j<A.points;j++){
//Find the same degree
//Carry out row exchange for nodes with the same degree

if(B.weight[i] == A.weight[j]){//Notice that this is when the degree of B equals the degree of A
//Row exchange
if(i!=j){//If I= J exchange, otherwise skip (do not exchange, it is the same as not changing)
SwapRows(i,j);//Replace and wrap rows first. Note: after rows are exchanged, the corresponding columns must also change (it can be understood that the order of row and column nodes must be consistent)
}

//Exchange columns from top to bottom, take i as the row, and keep approaching the structure of the second graph
if(i!=j){

if(SwapColumns(i,i,j)==false){//Swap column
cout<<"Cannot adjust to the same adjacency matrix! Different structures!"<<endl;
return 0;
}

int list[MAX];
x=0;
//Determine whether the positions of non-zero vertices in the column are the same

//Two for loops are in I= J in case of

for(k=0;k<A.points;k++){//Find the points with different positions and put them into the list
if(A.Matrix[i][k]!=B.Matrix[i][k]){//Find out the position different from B in Figure A and record it in the list
list[x]=k;//Record different columns
x=x+1;
}
}

for(k=0;k<x;k=k+2){
if(SwapColumns(i,list[k],list[k+1])==false){//Column switching is accompanied by row switching
//0 1/2 3/4 5
cout<<"Cannot adjust to the same adjacency matrix! Different structures!"<<endl;
return 0;
}//Cyclic exchange column
SwapRows(list[k],list[k+1]);//Loop wrap
}
}

break;
}
}
}
cout<<"After detection, the two graphs are isomorphic!"<<endl;
return 0;
}
```

give an example:
The matrix transformation process of figure g and figure G 'is as follows:     Disadvantages of the code:  This is the problem of the above code. Now modify and optimize the above code;
The idea is as follows:
① We adjust the structure of figure G:
Adjust the degree of each row to G ', that is, move the points of graph G, that is, move the rows and columns in the matrix;
② After adjustment, immediately check whether the two matrices are the same. If they are different, exchange nodes with the same degree from top to bottom, and traverse all possibilities. After each exchange, check once to see whether the two matrices are the same
Therefore, add the following code to the function:
①:
An intermediate array C, (if false is still returned under this initial decision condition, subsequent decisions are made, and subsequent decisions require an array a in the most initial state)
Note that this array must also initialize the same degree as A
(if it is 0 without initialization, whether it is isomorphic cannot be determined)
②:
A function to which the degree of the matrix of the first graph is consistent with the degree of the second graph_ be_ similar():

``` void to_be_similar(){
for(i=0;i<B.points;i++){
for(j=i;j<C.points;j++){
if(B.weight[i] == C.weight[j]){//Notice that this is when the degree of B equals the degree of A
//Row exchange
if(i!=j){//If I= J exchange, otherwise skip (do not exchange, it is the same as not changing)
SwapRows(i,j);//Replace and wrap rows first. Note: after rows are exchanged, the corresponding columns must also change (it can be understood that the order of row and column nodes must be consistent)
SwapColumns(0,i,j);//Row changes must be accompanied by column changes
}
}
}
}
}//After executing this function, the degree structure of the two matrices is the same
```

③ : Judge():

``` bool Judge(){
for(i =0; i <C.points;i++){
for(j=0; j <B.points;j++){
if(C.Matrix[i][j]!=B.Matrix[i][j])
return false;
}
}
return true;
}
```

④ Exchange the same functions in the rows and the columns after the row exchange. Determine before the exchange. After the exchange, determine the function SwapColumnsAndRowsAndJudge():

``` bool SwapColumnsAndRowsAndJudge(){//The columns are exchanged directly according to the same degree of points. After each row and column exchange, it is necessary to determine whether the two matrices are the same
for(int x=0;x<C.points;x++){
//Judge before exchange
if(Judge()){
return true;
}
for(y=x;y<C.points;y++){//You don't have to go back to the previous judgment, so here y=x
if(x!=y&&C.weight[x]==C.weight[y]){//&&x!=y
SwapRowsTwo(x,y);
SwapColumnsTwo(x,y);
}
if(Judge()){
return true;
}
}
return false;
}

}
```

⑤ Two new row column permutation functions (direct replacement)
SwapRowsTwo():

```bool SwapRowsTwo(int i,int j){//Improved code
int k;

for(k=0;k<C.points;k++){//Exchange rows i and j of the matrix
int temp;
temp = C.Matrix[i][k];
C.Matrix[i][k]= C.Matrix[j][k];
C.Matrix[j][k]= temp;
}
int temp;
temp =C.weight[i];
C.weight[i]= C.weight[j];
C.weight[j]= temp;
return true;
}

```

⑥SwapColumnsTwo():

```SwapColumnsTwo(int i,int j){//Improved code
int k;
for(k=0;k<C.points;k++){
int temp;
temp =C.Matrix[k][i];
C.Matrix[k][i]= C.Matrix[k][j];
C.Matrix[k][j]= temp;
}
return true;
}
```

The complete code is as follows:

```#include<iostream>
#include<stdlib.h>
#define MAX 100
using namespace std;

int points;             //Number of vertices of adjacency matrix (i.e. matrix order)
int edges;              //Number of edges of adjacency matrix (i.e. number of non zeros of adjacency matrix / 2)
int Matrix[MAX][MAX];   //matrix
int weight[MAX];        //A collection of rows and degrees
};

int i,j,k,y;
AdjacencyMatrix A,B,C;//Define adjacency matrices A and B, adjust a to B and meet the necessary conditions of isomorphism, then a and B are isomorphic
//Three necessary conditions: ① the number of nodes is the same ② the number of sides is the same ③ the number of nodes with the same degree is the same

// (exchange rows)
//The row position exchange function returns true for normal exchange. The row column exchange here is for figure A
bool SwapRows(int i,int j){
int k;
//Row exchange
for(k=0;k<A.points;k++){//Exchange rows i and j of the matrix
int temp;
temp = A.Matrix[i][k];
A.Matrix[i][k]= A.Matrix[j][k];
A.Matrix[j][k]= temp;
}
int temp;
//OK, the degree should also be exchanged
//This operation is equivalent to moving the point to a certain position,
//It is equivalent to the direct dragging of the three-dimensional world, that is, his points are stacked (or in improper order), and then we spread (or move) his points and place them again according to some rules (this rule makes the structure (matrix) of the current graph close to the target graph)
//Remember to change the degree after line exchange
temp =A.weight[i];
A.weight[i]= A.weight[j];
A.weight[j]= temp;
return true;
}

bool SwapRowsTwo(int i,int j){//Improved code
int k;

for(k=0;k<C.points;k++){//Exchange rows i and j of the matrix
int temp;
temp = C.Matrix[i][k];
C.Matrix[i][k]= C.Matrix[j][k];
C.Matrix[j][k]= temp;
}
int temp;
temp =C.weight[i];
C.weight[i]= C.weight[j];
C.weight[j]= temp;
return true;
}

bool  SwapColumnsTwo(int i,int j){//Improved code
int k;
for(k=0;k<C.points;k++){
int temp;
temp =C.Matrix[k][i];
C.Matrix[k][i]= C.Matrix[k][j];
C.Matrix[k][j]= temp;
}
return true;
}

//(column exchange)

//The column position exchange function returns true for normal exchange and false for unable exchange
bool  SwapColumns(int currentLayer,int i,int j){//Why three parameters: in order to keep the previously modified trend unchanged
int k;
//Judge whether it can be exchanged

//The meaning of this loop is that I started from the first line, and our figure A should be the same as figure B. then, currentLayer is the current level
//It can be understood that it is synchronized to the current level. Then, if our columns are exchanged, if they are different, it will destroy the trend that we try to be close to the structure of figure B. we can't let it continue
//Because if we synchronize the first row in Figure A and figure B, and then figure a synchronizes with other rows in Figure B, we find that if the exchange result will affect the previous synchronization result
//So there's no isomorphism, that is, the two matrices can't be the same
for(k=0;k<currentLayer;k++){//Exchange columns i and j

if(A.Matrix[k][i]!=A.Matrix[k][j]){
//Cannot exchange, because exchange will affect the result of previous adjustment, so it is not identical.
return false;
}
}
//Perform column exchange
for(k=0;k<A.points;k++){
int temp;
temp =A.Matrix[k][i];
A.Matrix[k][i]= A.Matrix[k][j];
A.Matrix[k][j]= temp;
}
return true;
}

void to_be_similar(){
for(i=0;i<B.points;i++){
for(j=i;j<C.points;j++){
if(B.weight[i] == C.weight[j]){//Notice that this is when the degree of B equals the degree of A
//Row exchange
if(i!=j){//If I= J exchange, otherwise skip (do not exchange, it is the same as not changing)
SwapRowsTwo(i,j);//Replace and wrap rows first. Note: after rows are exchanged, the corresponding columns must also change (it can be understood that the order of row and column nodes must be consistent)
SwapColumnsTwo(i,j);//Row changes must be accompanied by column changes

}
break;
}
}
}
}//After executing this function, the degree structure of the two matrices is the same
bool Judge(){
for(i =0; i <C.points;i++){
for(j=0; j <B.points;j++){
if(C.Matrix[i][j]!=B.Matrix[i][j])
return false;
}
}
return true;
}

bool SwapColumnsAndRowsAndJudge(){//The columns are exchanged directly according to the same degree of points. After each row and column exchange, it is necessary to determine whether the two matrices are the same
for(int x=0;x<C.points;x++){
//Judge before exchange
if(Judge()){
return true;
}
for(y=x;y<C.points;y++){//You don't have to go back to the previous judgment, so here y=x
if(x!=y&&C.weight[x]==C.weight[y]){//&&x!=y
SwapRowsTwo(x,y);
SwapColumnsTwo(x,y);
}
if(Judge()){
return true;
}
}
return false;
}

}

//Comparison algorithm for quick sorting
int cmp( const void *a , const void *b ){
return *(int *)a - *(int *)b;
}

int main(){
cout<<"Please enter the degree (number of vertices) of the two graphs:"<<endl;
cin>>A.points>>B.points;
C.points=A.points;//Note that initialization is required here
//Judge the first necessary condition

if(A.points!=B.points){
cout<<"Different order! Different structures!"<<endl;
return 0;
}

cout<<"Please enter the adjacency matrix of the first graph:"<<endl;
A.edges = 0;
B.edges = 0;

//Input A and B matrices by adjacency matrix

for(i=0;i<A.points;i++){
for(j=0;j<A.points;j++){
cin>>A.Matrix[i][j];
C.Matrix[i][j]=A.Matrix[i][j];//Copy A to C and analyze with C
if(A.Matrix[i][j]==1){
A.edges++;
}
}
}

cout<<"Please enter the adjacency matrix of the second graph:"<<endl;
for(i=0;i<B.points;i++){
for(j=0;j<B.points;j++){
cin>>B.Matrix[i][j];
if(B.Matrix[i][j]==1){
B.edges++;
}
}
}

//Judge the second necessary condition

if(A.edges!=B.edges){
cout<<"The number of edges is different! Different structures!"<<endl;
return 0;
}

//Because it is an adjacency matrix, the number of edges (i.e. the number of non zeros of the adjacency matrix / 2)
//When assigning values to edges, we give edges + 1 when the value of the two-dimensional matrix is 1. Because it is an undirected graph, G[i][j] and G[j][i] are the same, so we need / 2
A.edges =A.edges/2;
B.edges =B.edges/2;
int Aweight[MAX];//MAX==100
int Bweight[MAX];

//Judge the third necessary condition
int x=0;
for(k=0;k<A.points;k++){//There are point points in figure A, and then the degrees of these points are calculated
int count=0;//Initialization degree is 0
for(y=0;y<A.points;y++){
if(A.Matrix[k][y]==1){ //There are edges, degree + 1. It is unnecessary to consider / 2 here, because it is for the current point K. A.Matrix[k][y]==1 means that K has edges for the Y point (change point)
count++;//Degree + 1
}
}
Aweight[x]= count;//After traversing the statistical degree, record it in a one-dimensional array
C.weight[x]= A.weight[x]=count;//Of course, you need to record the current degree in the weight array in the A data structure, and then x+1;
x=x+1;
}
qsort(Aweight,A.points,sizeof(Aweight),cmp);
//Call system quick sort algorithm
//The meaning of sorting is: because the degree of the first point is uncertain, we can sort the array from small to large (or from large to small). After sorting, the array is regular
//Then, sort the array of recording point degrees in Figure B from small to large (or from large to small). After sorting, see whether it meets the following requirements:
//The third of the three necessary conditions of isomorphic graphs: the same number of nodes with the same degree

x=0;
//Do the same for matrix B
for(k=0;k<B.points;k++){
int count=0;
for(y=0;y<B.points;y++){
if(B.Matrix[k][y]==1){
count++;
}
}
Bweight[x]= count;
B.weight[x++]=count;
}
qsort(Bweight,B.points,sizeof(Bweight),cmp);//Call system quick sort algorithm
//Determine whether the third condition is met
for(k=0;k<A.points;k++){
if(Aweight[k]!=Bweight[k]){
cout<<"The degree of the edge is different! Different structures!"<<endl;
return 0;
}
}
//The matrix may be isomorphic at the beginning, and then, due to the different order of points, the matrix is different. At this time, we only need to exchange the rows and columns of the matrix and traverse all possibilities to see whether the same effect of the two matrices can be achieved

to_be_similar();
if(	SwapColumnsAndRowsAndJudge()){
cout<<"After detection, the two graphs are isomorphic!"<<endl;
return 0;
}

//Perform matrix transformation

//If the three conditions are met, the final verification operation is carried out: transform the matrix of the first graph to make its structure close to the second graph
//Moreover, if the operation process is not interrupted due to the wrong judgment of the row column exchange operation (that is, the row column exchange cannot be changed into the second graph, and then it is interrupted)

//Adjust matrix A to matrix B. please note that the following operations column exchange must be accompanied by row exchange. Why: because although there is not much correlation between the rows and columns of the matrix, even if row exchange and column exchange do not change the mapping relationship between their points
//Nor does it say that columns must be exchanged after rows are exchanged, but in the matrix representing the graph, the order of points is meaningful;
for(i=0;i<B.points;i++){
for(j=i;j<A.points;j++){
//Find the same degree
//Carry out row exchange for nodes with the same degree

if(B.weight[i] == A.weight[j]){//Notice that this is when the degree of B equals the degree of A
//Row exchange
if(i!=j){//If I= J exchange, otherwise skip (do not exchange, it is the same as not changing)
SwapRows(i,j);//Replace and wrap rows first. Note: after rows are exchanged, the corresponding columns must also change (it can be understood that the order of row and column nodes must be consistent)
}

//Exchange columns from top to bottom, take i as the row, and keep approaching the structure of the second graph
if(i!=j){

if(SwapColumns(i,i,j)==false){//Swap column
cout<<"Cannot adjust to the same adjacency matrix! Different structures!"<<endl;
return 0;
}

int list[MAX];
x=0;
//Determine whether the positions of non-zero vertices in the column are the same

//Two for loops are in I= J in case of

for(k=0;k<A.points;k++){//Find the points with different positions and put them into the list
if(A.Matrix[i][k]!=B.Matrix[i][k]){//Find out the position different from B in Figure A and record it in the list
list[x]=k;//Record different columns
x=x+1;
}
}

for(k=0;k<x;k=k+2){
if(SwapColumns(i,list[k],list[k+1])==false){//Column switching is accompanied by row switching
//0 1/2 3/4 5
cout<<"Cannot adjust to the same adjacency matrix! Different structures!"<<endl;
return 0;
}//Cyclic exchange column
SwapRows(list[k],list[k+1]);//Loop wrap
}
}

break;
} //This is I= When J, he will modify the exchange, and then I think if the degree is the same, can we also exchange rows and columns
}
}
cout<<"After detection, the two graphs are isomorphic!"<<endl;
return 0;
}
```

Test drawings are g and G '  Matrix change process: Test: Test data:
0 1 0 0 0 0
1 0 1 0 0 0
0 1 0 1 0 1
0 0 1 0 1 0
0 0 0 1 0 0
0 0 1 0 0 0

0 1 0 0 0 0
1 0 1 0 0 0
0 1 0 1 0 0
0 0 1 0 1 1
0 0 0 1 0 0
0 0 0 1 0 0  test data
0 1 0 0 0 0
1 0 1 0 0 0
0 1 0 1 0 0
0 0 1 0 1 1
0 0 0 1 0 0
0 0 0 1 0 0

0 1 0 0 0 0
1 0 1 0 0 1
0 1 0 1 0 0
0 0 1 0 1 0
0 0 0 1 0 0
0 1 0 0 0 0

Test results: 5. Time complexity and space complexity of the algorithm
By code: O(T1)=N^2 O(T2)=N*logN O(T3)=N^2 O(T4)=N*logN O(T5)=N   O(T6)=N^2* N=N^3 O(T7)=N^2 *N=N^3 Assuming k=N, the execution times of the for loop in this layer is N/2
SwapColumns function: if currentLayer is N, the number of executions of SwapColumns is:
N+N；
The number of executions of SwapRows function is N;
Therefore, the time complexity of for (k = 0; K < x; k = K + 2) is N/2*(N+N)=N^2
Since there are two for loops outside, the time complexity here is O(T8)=N^4   O(T9)=N*N^2
Therefore, its time complexity is:
O(T)=O(T1)+......+O(T9)=N^4
Space complexity:
O(T)=N^2

Reference blog: https://blog.csdn.net/tb20677206/article/details/71600508#comments_ nineteen million eighty-six thousand eight hundred and five

Posted on Fri, 26 Nov 2021 02:10:15 -0500 by kanika