I have managed to write my own minimum_factorization(X, U, C)
, where X is a given ground possibly cyclic term, C is minimum system of equations inluding U= A such that X and A are equivalent
when fully expanded.
The Current version may contain bugs.
% ?- A=f(B, 0), B=f(A, 1), factorization(f(A, B), U, F).
%@ A = f(f(A, 1), 0),
%@ B = f(A, 1),
%@ F = [U=f(_A, _B), _A=f(_B, _C), _C=0, _B=f(_A, _D), _D=1].
% ?- minimum_factorization(f(f(a), f(a)), U, L).
%@ L = [U=f(_A, _A), _A=f(_B), _B=a].
% ?- minimum_factorization(f(f(a), f(b)), U, L).
%@ L = [U=f(_A, _B), _B=f(_C), _C=b, _A=f(_D), _D=a].
% ?- A=f(B, B), B=f(A, A), minimum_factorization(f(A, B), U, F).
%@ A = B, B = f(_S1, _S1), % where
%@ _S1 = f(f(_S1, _S1), f(_S1, _S1)),
%@ F = [U=f(U, U)].
% ?- A=f(B, 0), B=f(A, 1), minimum_factorization(f(A, B), U, F).
%@ A = f(f(A, 1), 0),
%@ B = f(A, 1),
%@ F = [U=f(_A, _B), _A=f(_B, _C), _C=0, _B=f(_A, _D), _D=1].
minimum_factorization(T, S, L):-
factorization(T, S, L0),
minimize(L0, L).
%
minimize(X, Y):- select(U=_, X, X0),
select(V=_, X0, X1),
U \== V,
simulate(U, V, X, [], Cs),
!,
unify_cluster_list(Cs),
sort(X0, X1),
minimize(X1, Y).
minimize(X, X).
% ?- A=f(B, 0), B=f(A, 1), factorization(g(A,B), V, [], U, [], V).
% ?- A=f(B, 0), B=f(A, 1), factorization(g(A,B), V, C).
% ?- A=f(B, 0), B=f(A, 1), factorization(f(A,B), V, C).
factorization(X, V, C):- factorization(X, V, [], C, [], _).
%
factorization(X, _, _, _, _, _):- var(X), !, throw(unexpected_variable).
factorization(X, V, C, C, H, H):- member(U=T, H), T == X, !, V=U.
factorization(X, V, C, [V=U|C1], H, H1):- X=..[F|Xs],
factorization_list(Xs, Vs, C, C1, [V=X|H], H1),
U =..[F|Vs].
%
factorization_list([], [], C, C, H, H).
factorization_list([X|Xs], [V|Vs], C, C0, H, H0):-
factorization(X, V, C, C1, H, H1),
factorization_list(Xs, Vs, C1, C0, H1, H0).
%
unify_cluster([]):-!.
unify_cluster([_]):-!.
unify_cluster([X, X|R]):- unify_cluster([X|R]).
%
unify_cluster_list([]).
unify_cluster_list([C|Cs]):-unify_cluster(C), unify_cluster_list(Cs).
%
get_target(U, A, X):- member(V=A, X), U==V, !.
% ?- simulate(U, V, [U=a, V=a], [], Cs).
simulate(U, V, X, Cs, Cs0):-
get_target(U, A, X),
get_target(V, B, X),
functor(A, F, N),
functor(B, F, N),
A=..[_|As],
B=..[_|Bs],
union_find(U, V, Cs, Cs1),
simulate_list(As, Bs, X, Cs1, Cs0).
%
simulate_list([], [], _, Cs, Cs):-!.
simulate_list([A|As], [B|Bs], X, Cs, Cs0):-
( in_same_cluster(A, B, Cs) -> Cs1 = Cs
; simulate(A, B, X, Cs, Cs1)
),
simulate_list(As, Bs, X, Cs1, Cs0).
%
in_same_cluster(U, V, [C|_]):-
member(X, C), X==U,
member(Y, C), Y==V,
!.
in_same_cluster(U, V, [_|Cs]):- in_same_cluster(U, V, Cs).
% ?- union_find(A, B, [], X), union_find(C, B, X, Y).
union_find(X, Y, Cs, Ds):-
find_cluster(X, C, Cs, Cs0),
( member(U, C), U==Y -> Ds =[C|Cs0]
; find_cluster(Y, C0, Cs0, Cs1),
append(C0, C, C1),
Ds =[C1|Cs1]
).
%
find_cluster(X, C, [], []):-!, C=[X].
find_cluster(X, C, [D|Cs], Cs):-member(B, D), B==X, !, C=D.
find_cluster(X, C, [D|Cs], [D|Ds]):-find_cluster(X, C, Cs, Ds).