Trying to solve the isomorphic graphs problem here.
Assignment info:
- Determine whether 2 undirected graphs are isomorphic.
- No isolated vertices.
- Number of vertices is less than 30
Edges of graphs are given as predicates, i.e.
e(1, 2). f(1, 2).
I'm trying to use the following approach:
- For every pair of edges (i.e. for every edge from graph 1 and 2)
- Try to bind the vertices of 2 edges
- If binding of vertices is impossible (i.e. another binding with one of the vertex already exists), then backtrack and try another pair of edges.
- Otherwise add binding and continue with the rest of graphs (i.e. one edge from each graph is removed and procedure is applied again).
Procedure recurs unless both graphs are empty (meaning that all vertices were bound from one graph to the other one) meaning a success. Otherwise procedure should always fail (i.e. no other binding combinations available, etc.)
My code seems to be working but for small graphs only (guess because it tries all the pairs :) ).
So if anyone knows how it's possible to optimize the code (I believe that several cuts can be inserted and that try_bind
can be written in better way) or can tell a better approach thanks in advance.
P.s. for checking non-isomorphism I know that we can check invariants and etc. It doesn't really matter for now.
Code:
%define graph, i.e. graph is a list of edges
graph1(RES):-findall(edge(X,Y), e(X, Y), RES).
graph2(RES):-findall(edge(X,Y), f(X, Y), RES).
%define required predicate
iso:-graph1(G1), graph2(G2), iso_acc(G1, G2, [], _).
%same as above but outputs result
iso_w:-graph1(G1), graph2(G2), iso_acc(G1, G2, [], RES_MAP), write(RES_MAP).
iso_acc([], [], MAP, RES):-append(MAP, [], RES), !.
iso_acc([X|X_Rest], Y_LS, MAP, RES_MAP):-
select(Y, Y_LS, Y_Rest),
bind(X, Y, MAP, UPD_MAP),
iso_acc(X_Rest, Y_Rest, UPD_MAP, RES_MAP).
% if edges bind is successful then in RES or UPD_MAP updated binding map is returned (may return the same map
% if bindings are already defined), otherwise fails
bind([], [], MAP, RES):-append(MAP, [], RES), !.
bind(edge(X1, Y1), edge(X2, Y2), MAP, UPD_MAP):-
try_bind(b(X1, X2), MAP, RES),
try_bind(b(Y1, Y2), RES, UPD_MAP).
bind(edge(X1, Y1), edge(X2, Y2), MAP, UPD_MAP):-
try_bind(b(X1, Y2), MAP, RES),
try_bind(b(Y1, X2), RES, UPD_MAP).
%if an absolute member, we're OK (absolute member means b(X,Y) is already defined
try_bind(b(X, Y), MAP, UPD_MAP):-
member(b(X, Y), MAP),
append(MAP, [], UPD_MAP), !.
%otherwise check that we don't have other binding to X or to Y
try_bind(b(X, Y), MAP, UPD_MAP):-
member(b(X, Z), MAP),
%check if Z != Y
Z=Y,
append(MAP, [], UPD_MAP).
try_bind(b(X, Y), MAP, UPD_MAP):-
member(b(W, Y), MAP),
%check if W == X
W=X,
append(MAP, [], UPD_MAP).
%finally if we not an absolute member and if no other bindings to X and Y we add new binding
try_bind(b(X, Y), MAP, UPD_MAP):-
not(member(b(X, Z), MAP)),
not(member(b(W, Y), MAP)),
append([b(X, Y)], MAP, UPD_MAP).