%%%%%%%%%%%%%%
%
%   eqfirst(Cin, Cout) - Cin is a conjunction of clauses.  Put
%   any positive equality units at the beginning of the conj.
%
%%%%%%%%%%%%%%

eqfirst(Cin, Cout) :-
    eqf(Cin, true, true, EQ, NEQ),
    append_and(EQ, NEQ, Cout).

eqf(X and Y, Ein, Nin, Eout, Nout) :-
    !,
    eqf(X, Ein, Nin, E1, N1),
    eqf(Y, E1, N1, Eout, Nout).
eqf(X=Y, Ein, Nin, Eout, Nin) :-
    !,
    andon(Ein, X=Y, Eout).
eqf(F, Ein, Nin, Ein, Nout) :-
    andon(Nin, F, Nout).

%%%%%%%%%%%%%
%
%   oron and andon
%
%%%%%%%%%%%%%

oron(false, X, X) :- !.
oron(X, Y, X or Y).

andon(true, X, X) :- !.
andon(X, Y, X and Y).

%%%%%%%%%%%%%%%%
%
%    append_and(L1, L2, Lout) - It is assumes that L1 and L2 are
%    left associated trees of and's.  Result is left associated.
%
%%%%%%%%%%%%%%%%

append_and(_, false, false) :-
    !.
append_and(false, _, false) :-
    !.
append_and(X, true, X) :-
    !.
append_and(true, X, X) :-
    !.
append_and(X, and(Y, Z), and(W, Z)) :-
    !,
    append_and(X, Y, W).
append_and(X, Y, and(X, Y)).

%%%%%%%%%%%%%%%%
%
%    append_or(L1, L2, Lout) - It is assumes that L1 and L2 are
%    left associated trees of or's.  Result is left associated.
%
%%%%%%%%%%%%%%%%

append_or(_, true, true) :-
    !.
append_or(true, _, true) :-
    !.
append_or(X, false, X) :-
    !.
append_or(false, X, X) :-
    !.
append_or(X, or(Y, Z), or(W, Z)) :-
    !,
    append_or(X, Y, W).
append_or(X, Y, or(X, Y)).

%%%%%%%%%%%%%%
%
%    cleanup(Fin,Fout) - Simplify Fin bu getting rid of "true",
%    "false", "X=X", and "~(X=X)".
%
%%%%%%%%%%%%%%

cleanup(A and B,Fout) :-
    !,
    cleanup(A,A1),
    cleanup(B,B1),
    reduce4(A1 and B1,Fout),
    !.
cleanup(A or B,Fout) :-
    !,
    cleanup(A,A1),
    cleanup(B,B1),
    reduce4(A1 or B1,Fout),
    !.
cleanup(~true,false) :-
    !.
cleanup(~false,true) :-
    !.
cleanup(X=X,true) :-
    !.
cleanup(~(X=X),false) :-
    !.
cleanup(X,X).

reduce4(true and X,X) :- !.
reduce4(X and true,X) :- !.
reduce4(false and _,false) :- !.
reduce4(_ and false,false) :- !.
reduce4(true or _,true) :- !.
reduce4(_ or true,true) :- !.
reduce4(false or X,X) :- !.
reduce4(X or false,X) :- !.
reduce4(X,X).

%%%%%%%%%%%%%%
%
%    def(Def,Fin,Fout) - expand definition (if recursive, just
%			expand one level)
%    example:
%    def(all(x,all(y,p(x,y) iff r(x) and q(y))), p(a,b), r(a) and q(b))).
%
%%%%%%%%%%%%%%

def(D,Fin,Fout) :-
   predef(D,[],P,L,RS),
   taxsub(Fin,P,L,RS,Fout),
   !.

predef(all(X,G),Lin,P,Lout,RS) :-
    !,
    predef(G,[X|Lin],P,Lout,RS).
predef(G iff RS,Lin,P,Lout,RS) :-
    !,
    G =.. [P|Lout],
    alldiff(Lin),
    alldiff(Lout),
    seteq(Lin,Lout).
predef(G,_,_,_,_) :-
    write('predef: bad definition: '),
    write(G), nl.

/*
    pcllist(L) - Output a conjunctive formula 
		 without the top level ands.
*/

pcllist(and(X,Y)) :-
    pcllist(X),
    pcllist(Y),
    !.

pcllist(X) :-
    write(X),
    nl,
    !.

/*
    pdisj(L) - Output a disjunctive formula without the top level ors.
*/

pdisj(or(X,Y)) :-
    pdisj(X),
    pdisj(Y),
    !.

pdisj(X) :-
    write(X),
    nl,
    !.

/*
    printdisj(D) - Output a disjunctive formula, printing the
    top level or's.
*/

printdis(X or Y) :-
    !,
    printdis(X), write(' or'), nl,
    printdis(Y).
printdis(X) :-
    write(X).

%%%%%%%%%%%%%%%
%
%   taxsub(F1, S, L, F2, G) - Perform an iff substitution in F1.
%   Example: the equivalence is all(x, all(y, p(x, y) iff q(x) or r(y))).
%
%   All occurrences of p in F1 are rewritten.
%   S is p
%   L is [x, y]
%   F2 is q(x) or r(x)
%   G is the result
%
%%%%%%%%%%%%%%%

taxsub(X, Y, Z, W, V) :-
    X =.. [X1|X2],
    X1 == Y,
    simsub(Z, W, X2, V),
    !.
taxsub(and(X1, X2), Y, Z, W, and(V1, V2)) :-
    taxsub(X1, Y, Z, W, V1),
    taxsub(X2, Y, Z, W, V2),
    !.
taxsub(or(X1, X2), Y, Z, W, or(V1, V2)) :-
    taxsub(X1, Y, Z, W, V1),
    taxsub(X2, Y, Z, W, V2),
    !.
taxsub(imp(X1, X2), Y, Z, W, imp(V1, V2)) :-
    taxsub(X1, Y, Z, W, V1),
    taxsub(X2, Y, Z, W, V2),
    !.
taxsub(iff(X1, X2), Y, Z, W, iff(V1, V2)) :-
    taxsub(X1, Y, Z, W, V1),
    taxsub(X2, Y, Z, W, V2),
    !.
taxsub(all(X1, X2), Y, Z, W, all(X1, V2)) :-
    taxsub(X2, Y, Z, W, V2),
    !.
taxsub(exists(X1, X2), Y, Z, W, exists(X1, V2)) :-
    taxsub(X2, Y, Z, W, V2),
    !.
taxsub(~(X1), Y, Z, W, ~(V1)) :-
    taxsub(X1, Y, Z, W, V1),
    !.
taxsub(X, _, _, _, X) :-
    !.

/* 
    assor - left associate a binary tree of 'or' 
*/

assor(or(X1, Y1), F1, F3) :-
    !, 
    assor(X1, F1, F2), 
    assor(Y1, F2, F3).
assor(X, F1, X) :-
    F1 == [], 
    !.
assor(X, F1, or(F1, X)).

/* 
    assand - left associate a binary tree of 'and' 
*/

assand(and(X1, Y1), F1, F3) :-
    !, 
    assand(X1, F1, F2), 
    assand(Y1, F2, F3).
assand(X, F1, X) :-
    F1 == [], 
    !.
assand(X, F1, and(F1, X)).

