:-op(140,fy,neg).
:-op(160, xfx, [and, or, imp, revimp, nand, nor, notimp, notrevimp]).

member(X,[X|_]).
member(X,[_|Xs]) :- member(X,Xs).

remove(_X,[],[]).
remove(X,[X|Xs],Ys) :-
	remove(X,Xs,Ys).
remove(X,[Y|Xs],[Y|Ys]) :-
	X \== Y,
	remove(X,Xs,Ys).

append([],Xs,Xs).
append([X|Xs],Ys,[X|Zs]) :-
	append(Xs,Ys,Zs).

is_unary(neg neg _X).
is_unary(neg true).
is_unary(neg false).

is_conjunctive(_X and _Y).
is_conjunctive(neg(_X or _Y)).
is_conjunctive(neg(_X imp _Y)).
is_conjunctive(neg(_X revimp _Y)).
is_conjunctive(neg(_X nand _Y)).
is_conjunctive(_X nor _Y).
is_conjunctive(_X notimp _Y).
is_conjunctive(_X notrevimp _Y).

is_disjunctive(neg(_X and _Y)).
is_disjunctive(_X or _Y).
is_disjunctive(_X imp _Y).
is_disjunctive(_X revimp _Y).
is_disjunctive(_X nand _Y).
is_disjunctive(neg(_X nor _Y)).
is_disjunctive(neg(_X notimp _Y)).
is_disjunctive(neg(_X notrevimp _Y)).

component(neg neg X, X).
component(neg true, false).
component(neg false, true).

components(X and Y, X,Y).
components(neg(X and Y), neg X, neg Y).
components(X or Y,X,Y).
components(neg(X or Y), neg X, neg Y).
components(X imp Y, neg X, Y).
components(neg(X imp Y), X, neg Y).
components(X revimp Y, X, neg Y).
components(neg(X revimp Y), neg X, Y).
components(X nand Y, neg X, neg Y).
components(neg (X nand Y), X,Y).
components(X nor Y,neg X, neg Y).
components(neg(X nor Y), X,Y).
components(X notimp Y, X, neg Y).
components(neg(X notimp Y), neg X, Y).
components(X notrevimp Y, neg X, Y).
components(neg(X notrevimp Y), X, neg Y). 

stepDNF([C|Cs],NCs) :-
	member(Formula,C),
	is_unary(Formula),
	component(Formula,Newformula),
	remove(Formula,C,NC0),
	append(NC0,[Newformula],NC),
	append(Cs,[NC],NCs).
stepDNF([C|Cs],NCs) :-
	member(Alpha,C),
	is_conjunctive(Alpha),
	components(Alpha,Alpha1,Alpha2),
	remove(Alpha,C,NC0),
	append(NC0,[Alpha1,Alpha2],NC),
	append(Cs,[NC],NCs).
stepDNF([C|Cs],NCs) :-
	member(Beta,C),
	is_disjunctive(Beta),
	components(Beta,Beta1,Beta2),
	remove(Beta,C,NC0),
	append(NC0,[Beta1],NC1),
	append(NC0,[Beta2],NC2),
	append(Cs,[NC1,NC2],NCs).	
stepDNF([C|Cs],[C|NCs]) :-
	stepDNF(Cs,NCs).

% tests
:-stepDNF([[neg neg p]],[[p]]).
:-stepDNF([[p or q]],[[p],[q]]).
:-stepDNF([[p and q]],[[p,q]]).
:-stepDNF([[(p imp (q imp r)) imp ((p imp q) imp (p imp r))]],_X).

expand1(Cs,Cs).
expand1(Cs,NCs) :-
	stepDNF(Cs,Cs0),
	expand1(Cs0,NCs).

expand2(Cs,NCs) :-
	stepDNF(Cs,Cs0),
	expand2(Cs0,NCs).
expand2(Cs,Cs).

towards_DNF(X,Y) :- expand1([[X]],Y).

dualclauseform(X,Y) :- expand2([[X]],Y),
		       !.

% tableau prover

closed([]).
closed([B|Bs]) :-
	member(false,B),
	closed(Bs).
closed([B|Bs]) :-
	member(X, B),
	member(neg X, B),
	closed(Bs).

tableau_thm(X) :-
	expand2([[neg X]],Y),
	closed(Y).

expand_and_close(T) :-
	closed(T).
expand_and_close(T0) :-
	stepDNF(T0,T1),
	expand_and_close(T1).

tableau_thm2(X) :-
	expand_and_close([[neg X]]).

% tests
:-tableau_thm(x or neg x).
:-tableau_thm2(x or neg x).
:-tableau_thm2(((p and (q imp (r or s))) imp (p or q))).
:-tableau_thm(((p and (q imp (r or s))) imp (p or q))).