
%%%%%%%%%%%%%%%
%
%    taut_check(X, Y) - It is assumed that X is a conjunction of clauses.
%    Clauses that are tautologies are reduced to "true".
%    Result is Y.
%
%%%%%%%%%%%%%%%

taut_check(and(X, Y), and(X1, Y1)) :-
    !,
    taut_check(X, X1),
    taut_check(Y, Y1).
taut_check(X, true) :-
    tautology(X),
    !.
taut_check(X, X) :-
    !.

%%%%%%%%%%%%%%%
%
%    tautology(X) - Check if X is a tautology.
%    X must be left associated.
%
%%%%%%%%%%%%%%%

tautology(or(X, Y)) :-
    tlc(X, Y),
    !.
tautology(or(X, _)) :-
    !,
    tautology(X).

tlc(or(_, X), Y) :-
    taut_lits(X, Y),
    !.
tlc(or(X, _), Z) :-
    !,
    tlc(X, Z).
tlc(X, Y) :-
    taut_lits(X, Y).

taut_lits(A, ~B) :-
     A == B,
     !.
taut_lits(~A, B) :-
     A == B,
     !.
taut_lits(~(A=B), C=D) :-
     commutative(=),
     A == D,
     B == C,
     !.
taut_lits(A=B, ~(C=D)) :-
     commutative(=),
     A == D,
     B == C,
     !.

%%%%%%%%%%%%%%%
%
%    merge(X, Y) - Merge literals of a clause (1st occurrence kept).
%
%%%%%%%%%%%%%%%

merge(or(X, Y), Z) :-
    occurcl(X, Y),
    !,
    merge(X, Z).
merge(or(X, Y), or(Z, Y)) :-
    !,
    merge(X, Z).
merge(X, X) :-
    !.

occurcl(or(_, Y), X) :-
    same_lits(Y, X),
    !.
occurcl(or(X, _), Z) :-
    !,
    occurcl(X, Z).
occurcl(X, Y) :-
    same_lits(X,Y),
    !.

same_lits(A, B) :-
     A == B,
     !.
same_lits(A=B, C=D) :-
     commutative(=),
     A == D,
     B == C,
     !.

%%%%%%%%%%%%%%%
%
%    instant(Cin, Cout) - Simplify with (x=x).
%
%    (Method is not resolution.  It works by
%    finding ~(var=term) literals and substituting term for var
%    throughout the clause.)  It leaves the ~(t=t) literals
%    in the clause -- they should be taken care of later
%    by the "cleanup" procedure.
%
%%%%%%%%%%%%%%%

instant(Cin, Cout) :-
    instant_1(Cin, Cin, Cout).

instant_1(or(X, Y), Cin, Cout) :-
    negeq(Y, dummy(X, Cin), dummy(X1, C1)),
    !,
    instant_1(X1, C1, Cout).
instant_1(or(X, _), Cin, Cout) :-
    !,
    instant_1(X, Cin, Cout).
instant_1(X, Cin, Cout) :-
    negeq(X, Cin, Cout),
    !.
instant_1(_, Cin, Cin).

negeq(~(X=Y), Cin, Cout) :-
    tpvar(X),
    !,
    \+ occur(X, Y),
    subst(X, Cin, Y, Cout).
negeq(~(X=Y), Cin, Cout) :-
    tpvar(Y),
    !,
    \+ occur(Y, X),
    subst(Y, Cin, X, Cout).

%%%%%%%%%%%%%%%
%
%    subsume(C1, C2, Sin, Sout) - does C1  subsume C2?
%    Sin is the incomming substitution.  When called from
%    the outside, Sin will usually be [[], []].
%
%%%%%%%%%%%%%%%

subsume(or(X1, X2), C2, Sin, Sout) :-
    !,
    maplit(X2, C2, Sin, S1),
    subsume(X1, C2, S1, Sout),
    !.
subsume(X, C2, Sin, Sout) :-
    !,
    maplit(X, C2, Sin, Sout),
    !.

maplit(false, _, Sin, Sin) :-
    !.
maplit(_, true, _, [[], []]) :-
    !.
maplit(L, or(_, X2), Sin, Sout) :-
    halfmatch(L, X2, Sin, Sout).   % if fail here, try another mapping
maplit(L, or(X1, _), Sin, Sout) :-
    !,
    maplit(L, X1, Sin, Sout).
maplit(L, X, Sin, Sout) :-
    halfmatch(L, X, Sin, Sout).

%%%%%%%%%%%%%%%
%
%    subsumelist(L1, Lin, Lout) - transform clause list Lin to Lout
%    by rewriting to "true" those clauses that are subsumed by
%    clauses in L1.
%
%%%%%%%%%%%%%%%

subsumelist(and(X, Y), Lin, Lout) :-
    !,
    subsumelist(X, Lin, L1),
    subsumelist(Y, L1, Lout).
subsumelist(X, Lin, Lout) :-
    slc(X, Lin, Lout).

slc(C, and(X, Y), and(X1, Y1)) :-
    !,
    slc(C, X, X1),
    slc(C, Y, Y1).
slc(C, X, true) :-
    subsume(C, X, [[], []], _),
    !.
slc(_, X, X).

%%%%%%%%%%%%%%%
%
%   subdel(Lin, Lout) - Rewrite to 'true' any clauses in Lin that
%   are subsumed by other clauses in Lin.  The result is Lout.
%   Warning -- It is assumed that Lin is a left associated tree
%   of and's.
%
%%%%%%%%%%%%%%%

subdel(L and C, Lout) :-
    !,
    subdel(L, L1),
    subsumelist(L1, C, C1),
    sd(L1, C1, Lout).
subdel(C, C) :-
    !.

sd(L1, true, L1 and true) :-
    !.
sd(L1, C1, Lout and C1) :-
    subsumelist(C1, L1, Lout).

%%%%%%%%%%%%%%%
%
%    simplify(Lin, Lout) - Simplify a list of clauses:
%
%	simplify with x=x;
%	take care of t1=t1, ~(t1=t1);
%	remove false literals;
%	remove tautologies;
%	merge identical literals;
%
%%%%%%%%%%%%%%%

simplify(Lin, Lout) :-
    simplist(Lin, L1),
    taut_check(L1, L2),
    cleanup(L2, Lout),
    !.

simplist(and(L1, L2), and(L3, L4)) :-
    !,
    simplist(L1, L3),
    simplist(L2, L4).
simplist(Cin, Cout) :-
    instant(Cin, C1),
    cleanup(C1, C2),
    merge(C2, Cout),
    !.

%%%%%%%%%%%%%%%
%
%    newvars(Fin, Fout) - Transform Fin to Fout by renaming all
%    variables (for this procedure, a term T is a variable iff
%    tpvar(T) is true) to brand new variable names.
%
%%%%%%%%%%%%%%%

newvars(Fin, Fout) :-
    newvars_1(Fin, [], Fin, _, Fout),
    !.

newvars_1(F, Lin, Fin, Lout, Fout) :-
    \+ atomic(F),
    !,
    F =.. FL,
    newvars_1_list(FL, Lin, Fin, Lout, Fout),
    !.
newvars_1(F, Lin, Fin, [F|Lin], Fout) :-
    tpvar(F),
    \+ member(F, Lin),
    !,
    gensym(xx, Y),
    subst(F, Fin, Y, Fout),
    !.
newvars_1(_, Lin, Fin, Lin, Fin) :-
    !.

newvars_1_list([H|T], Lin, Fin, Lout, Fout) :-
    newvars_1(H, Lin, Fin, L1, F1),
    newvars_1_list(T, L1, F1, Lout, Fout),
    !.
newvars_1_list([], Lin, Fin, Lin, Fin) :-
    !.

%%%%%%%%%%%%%%%
%
%    normalize(Fin, Fout) - rename all varaibles in Fin, starting with
%    x1, x2, ... .  The result is Fout.  No assumptions are made about
%    the form of Fin.
%
%%%%%%%%%%%%%%%

normalize(Fin, Fout) :-
    norm_table(Fin, [[], []], [VO, VN], 0, _),
    simsub(VO, Fin, VN, Fout).

norm_table(Fin, Vin, Vout, Nin, Nout) :-
    \+ atomic(Fin),
    !,
    Fin =.. [_|T],
    norm_table_args(T, Vin, Vout, Nin, Nout).
norm_table(Fin, Vin, Vout, Nin, Nout) :-
    tpvar(Fin),
    !,
    norm_tpvar(Fin, Vin, Vout, Nin, Nout).
norm_table(_, Vin, Vin, Nin, Nin).

norm_tpvar(Fin, [VOin, VNin], [VOin, VNin], Nin, Nin) :-
    member(Fin, VOin),
    !.
norm_tpvar(Fin, [VOin, VNin], [[Fin|VOin], [XN|VNin]], Nin, Nout) :-
    Nout is Nin + 1,
    integername(Nout, [], IN),
    append("x", IN, L),
    name(XN, L).

norm_table_args([H|T], Vin, Vout, Nin, Nout) :-
    norm_table(H, Vin, V1, Nin, N1),
    norm_table_args(T, V1, Vout, N1, Nout).
norm_table_args([], Vin, Vin, Nin, Nin).

%%%%%%%%%%%%%%%
%
%    normalize_list(Fin, Fout) - It is assumed that Fin is a conjunction
%    For each conjunct, call "normalize" to rename the variables.
%
%%%%%%%%%%%%%%%

normalize_list(X and Y, X1 and Y1) :-
    !,
    normalize_list(X, X1),
    normalize_list(Y, Y1),
    !.
normalize_list(X, Y) :-
    normalize(X, Y),
    !.

%%%%%%%%%%%%%%%
%
%    clausify(Fin, Fout) - several different versions
%
%%%%%%%%%%%%%%%

clausify(Fin, Fout) :-
    !,
    unique_vars(Fin, F2),
    skolem(F2, [], f, F3),
    delall(F3, F4),
    cnf(F4, F5),
    normalize_list(F5, Fout).

clausify2(Fin, Fout) :-
    !,
    unique_vars(Fin, F0),
    skolem(F0, [], f, F1),
    delall(F1, F2),
    cnf(F2, Fout).

clausify_mini(Fin, Fout) :-
    !,
    unique_vars(Fin, F0),
    nnf2(F0, F1),
    mini7(F1, F2),
    skolem(F2, [], f, F3),
    delall(F3, F4),
    cnf(F4, Fout).
