I hope @kuniaki.mukai will like this post. Now that
we are past this generic type of compare/3, where
rep/2
is some representation:
rep_compare(C, X, Y) :-
rep(X, A),
rep(Y, B),
compare(C, A, B).
We can now switch gears, and leave naish/2
behind
us, and turn to Deutsch-Schorr-Waite marking algorithm,
that can give us as well a numbering of cycle nodes:
deutsch(X, Y) :-
deutsch(X, Y, [], _).
deutsch(X, V, S, S) :- compound(X),
member(v(Z,T,Y,W), S), X == Z, !,
(var(T) -> V = Y; V = T),
W = 1.
deutsch(X, Y, S, T) :- compound(X), !,
length(S, N),
X =.. [F|L],
foldl(deutsch, L, R, [v(X,V,'$IDX'(N),W)|S], T),
Y =.. [F|R],
(var(W) -> V = Y; V = '$IDX'(N)).
deutsch(X, X, S, S).
The Schorr-Waite graph marking algorithm appeared first in
about 1968; it is also attributed to Peter Deutsch. So I am
calling the above predicate deutsch/2
because it is a shorter
name then schorr_waite/2
or deutsch_schorr_waite/3
.
What can it do? Well it detects sharing and is thus more
resilient to examples such as hydra/2
.
Naish has no sharing detection:
?- X = f(g(h(Z))), Y = k(X,X), naish(Y, T).
T = k(f(g(h(Z))), f(g(h(Z)))).
?- X = f(g(h(X))), Y = k(X,X), naish(Y, T).
T = k(f(g(h('$IDX'(1)))), f(g(h('$IDX'(1))))).
Deutsch has sharing detection:
?- X = f(g(h(Z))), Y = k(X,X), deutsch(Y, T).
T = k(f(g(h(Z))), f(g(h(Z)))).
?- X = f(g(h(X))), Y = k(X,X), deutsch(Y, T).
T = k(f(g(h('$IDX'(1)))), '$IDX'(1)).
You can also inspect the results with '$factorize_term'/3
,
to see sharing that is not shown in the top-level. This
gives yet another compare/3 which is a total order
and which is conservative and can deal with sharing,
when combined with the SWI-Prolog compare/3 in
a rep_compare/3
. But still expensive, not for practical
use, only for educational use.