%%% Recitation
%%% April 15th 2023

%%% G4ip: Contraction Free Inversion Calculus
%%% Just like you did in SML for the Homework but in Prolog.
%%% Prolog does all of the backtracking automatically.

% We start with right inversion

prove(A) :-
    rinv([],[],A). % . ; . =R> A

% rinv(G, O, A) is G ; O =R> A

rinv(G, O, and(A,B)) :-
        rinv(G, O, A),
        rinv(G, O, B).

rinv(G, O, top).

rinv(G, O, imp(A,B)) :-
    rinv(G, [A | O], B).

% From Rinv to Linv

rinv(G, O, atom(P)) :-
    linv(G, O, atom(P)).

%%% I missed this rule during recitation somehow
rinv(G, O, or(A,B)) :-
    linv(G, O, or(A, B)).

rinv(G, O, bot) :-
    linv(G, O, bot).

% linv(G,O,C) is G ; O =L> C+
% All left invertible formulas and
% all left invertible "implication bundles"

linv(G, [and(A,B) | O], C) :-
    linv(G, [A , B | O], C).

linv(G, [top | O], C) :-
    linv(G, O, C).

linv(G, [or(A,B) | O], C) :-
    linv(G, [A | O], C),
    linv(G, [B | O], C).

linv(G, [bot | O], C).

linv(G, [imp(top, A) | O], C) :-
    linv(G, [A | O], C).

linv(G , [imp(bot,A) | O], C) :-
    linv(G, O, C).

linv(G, [imp(and(A,B),C) | O], D) :-
    linv(G, [imp(A,imp(B,C)) | O], D).

linv(G, [imp(or(A,B),C) | O], D) :-
    linv(G, [imp(A,C) , imp(B,C) | O], D).

% Shift formulas that are not left invertible to gamma

linv(G, [atom(P) | O], C) :-
    linv([atom(P) | G], O, C).

linv(G, [imp(atom(P), A) | O], C) :-
    linv([imp(atom(P), A) | G], O, C).

linv(G, [imp(imp(A,B),C) | O], D) :-
    linv([imp(imp(A,B),C) | G], O, D).

linv(G, [], A) :-
    choice(G, A).

% "Choice"
% choice(G,O,A) is G =C> A

choice(G, atom(P)) :-
    member(atom(P), G).

% could've used ; as well to join
% both OR cases
choice(G, or(A,B)) :-
    rinv(G, [], A).

choice(G, or(A,B)) :-
    rinv(G, [], B).

choice(G, D) :-
    member(imp(atom(P), A), G), % do we have P in Gamma?
    member(atom(P), G), % does D actually use P? If not then it doesn't matoper
    delete(G, imp(atom(P), A), G2),
    linv(G2, [A], D).

choice(G, D) :-
    member(imp(imp(A,B),C), G),
    delete(G, imp(imp(A,B),C), G2),
    rinv(G2, [imp(B,C),A], B),
    linv(G2, [C], D).
