%%%%%%%%%%%%%%
%
%   mini7(Fin, Fout) -- convert to a conjunctive pseudo mini-scope form.
%
%    It is pseudo becuase different permutations of sequences of the
%    same quantifier are not attempted.
%    
%    If you want a disjunctive miniscope form of, for example, A, then
%       nnf2(~A, B), mini7(B, C), nnf(~C, D).
%
%%%%%%%%%%%%%%

mini7(F1 and G1, Hout) :-
    !,
    mini7(F1, F2),
    mini7(G1, G2),
    s3_and(F2, G2, Hout). % get reduced conjunctive form of (F2 and G2)
mini7(F1 or G1, Hout) :-
    !,
    mini7(F1, F2),
    mini7(G1, G2),
    s6_and(F2, G2, Hout). % get reduced conjunctive form of (F2 or G2)
mini7(F1 imp G1, Hout) :-
    !,
    nnf2(F1 imp G1, H),
    mini7(H, Hout).
mini7(A iff B, Hout) :-
    !,
    nnf2(~A, An),
    nnf2(~B, Bn),
    copy_new_vars(An, Anc),
    copy_new_vars(Bn, Bnc),
    mini7((Anc or B) and (A or Bnc), Hout).
mini7(~(A iff B), Hout) :-
    !,
    nnf2(~A, An),
    nnf2(~B, Bn),
    copy_new_vars(An, Anc),
    copy_new_vars(Bn, Bnc),
    mini7((A or B) and (Anc or Bnc), Hout).

mini7(exists(X, A), Hout ) :-
    !,
    nnf2(~exists(X,A), B),
    mini7(B, C),
    nnf(~C, D),
    rcnf_compact(D, Hout).

mini7(all(X, A), B) :-
    \+ free(X, A),
    !,
    mini7(A, B).
mini7(all(X, F and G), Hout) :-
    !,
    mini7(all(X, F), F1),
    mini7(all(X, G), G1),
    copy_new_vars(G1, G1c),
    s3_and(F1, G1c, Hout).
mini7(all(X,A iff B), Hout) :-
    !,
    nnf2(~A, An),
    nnf2(~B, Bn),
    copy_new_vars(An, Anc),
    copy_new_vars(Bn, Bnc),
    mini7(all(X,(Anc or B) and (A or Bnc)), Hout).
mini7(all(X,~(A iff B)), Hout) :-
    !,
    nnf2(~A, An),
    nnf2(~B, Bn),
    copy_new_vars(An, Anc),
    copy_new_vars(Bn, Bnc),
    mini7(all(X,(A or B) and (Anc or Bnc)), Hout).
mini7(all(X, F or G), Hout) :-
    compact_or(F or G, A),
    cnf(A, B),
    B = (_ and _),
    unique_vars(B, C),
    !,
    mini7(all(X, C), Hout).
mini7(all(X, A), Hout) :-
    !,
  % A is either a simple disjunction, quantified form, atomic, 
  % or negated atomic.
    ofd(X, A, false, false, B, C), % separate disjuncts without X
    mini7(B, D),                   % each disjunct in B has X free
    ofd(X, D, false, false, J, I), % separate disjuncts without X
    what_next(all(X, J), E),       % if J a conjunction, then dive back in
    mini7(C, F),                   % no disjunct in C or I has X free
    s6_and(E, I, K),               % result is conj form of (E or I or F)
    s6_and(K, F, Hout).

mini7(F, F) :-  
  % F is either atomic or negated atomic
    !.

%%%%%%%%%%%%%%
%
%   what_next(all(X, C), Hout)  -  if C is a conjunction, then all(X,C)
%   can be further reduced; otherwise do some equality simplification.
%   C is already in mini7 form.
%
%%%%%%%%%%%%%%

what_next(all(_, true), true) :-
    !.
what_next(all(_, false), false) :-
    !.
what_next(all(X, A and B), Hout) :-
    !,
    mini7(all(X, A and B), Hout).
what_next(all(X, A), A) :-
    \+ free(X, A),
    !.
what_next(all(X, A), Hout) :-
    !,
    eqreduce(all(X, A), Hout).

%%%%%%%%%%%%%%%
%
%    eqreduce(A, B)  
%       If A is of the form    all(x, ... or ~(x=a) or  ... ) 
%       then simplify by instantiation.
%
%%%%%%%%%%%%%%%

eqreduce(all(X, A), Hout) :-
    eqred1(X, A, H, C),  % fails if can't be reduced
    !,
    subst(X, H, C, Hout).
eqreduce(X, X).

eqred1(X, A or B, D, C) :-
    eqred1(X, A, A1, C),
    reduce4(A1 or B, D),
    !.
eqred1(X, A or B, D, C) :-
    eqred1(X, B, B1, C),
    reduce4(A or B1, D),
    !.
eqred1(X, ~(X=A), false, A) :-
    !.
eqred1(X, ~(A=X), false, A) :-
    !.

%%%%%%%%%%%%%%%
%
%    ofd(X, F, Fin, Nin, Fout, Nout) - Separate a disjunction into the
%    disjuncts in which X occurs free (Fout) and those in which it
%    doesn't (Nout).
%
%%%%%%%%%%%%%%%

ofd(Z, G1 or G2, Fin, Nin, Fout, Nout) :-
    !,
    ofd(Z, G1, Fin, Nin, F1, N1),
    ofd(Z, G2, F1, N1, Fout, Nout).
ofd(Z, F, Fin, Nin, Fout, Nin) :-
    free(Z, F),
    !,
    oron(Fin, F, Fout).
ofd(_, F, Fin, Nin, Fin, Nout) :-
    oron(Nin, F, Nout).

%%%%%%%%%%%%%%%
%
%   free(X, F) - Does the term X occur free in F?
%
%%%%%%%%%%%%%%%

free(X, Y) :-
    X == Y,
    !.
free(X, all(Y, _)) :-
    X == Y,
    !,
    fail.
free(X, exists(Y, _)) :-
    X == Y,
    !,
    fail.
free(_, F) :-
    atomic(F),
    !,
    fail.
free(X, F) :-
    F =.. L,
    freerec(X, L),
    !.

freerec(X, [H|_]) :-
    free(X, H),
    !.
freerec(X, [_|T]) :-
    freerec(X, T).

