Declaratieve Talen/oplossingenSluiting

Uit Wina Examenwiki
Naar navigatie springen Naar zoeken springen
% -- Deel 1
sluiting(Waar, Regels, Sluiting) :-
		select(Cond >> Cons, Regels, RemainingRegels),
		member2(Cond, Waar), !, 
		append(Waar, Cons, NewWaar0),
		list_to_set(NewWaar0, NewWaar1),
		sluiting(NewWaar1, RemainingRegels, Sluiting).
sluiting(X, _, X).

member2(L1, L2) :- intersection(L1, L2, L1).

% -- Deel 2

alleredundante(F, X) :-
	findall(Pad,
	(
		select(Cond >> Cons, F, AndereRegels),
		isredundant(Cond, AndereRegels, Cons, Pad0),
		Pad = redundant(Cond >> Cons, Pad0)
	),
	List),
	list_to_set(List, X).

isredundant(From, Regels, To, Pad) :-
	select(Cond >> Cons, Regels, AndereRegels),
	(
		member2(To, Cons) ->
			Pad = [Cond >> Cons],
			From = Cond
		;
			isredundant(From0, AndereRegels, To, Pad0),
			(
				member2(From0, Cons) ->
					Pad = [Cond >> Cons | Pad0],
					From = Cond
			;
				Pad = Pad0,
				From = From0
			)
	).

Andere oplossing, weliswaar veel lelijker maar het maakt gebruik van sluiting/3 in deel 2

%% Deel 1 %%

sluiting(VarSet,F,Sluiting) :-
    findall(Gevolg, (member(A>>Gevolg,F), set_diff(A,VarSet,[])), Gevolgen),
    concat(Gevolgen,EenLijst),
    append(VarSet,EenLijst,NieuwLijst),
    list_to_set(NieuwLijst,Stap),
    ( set_equals(Stap,VarSet) -> % geen nieuwe variabelen toegevoegd in laatste stap; sluiting gevonden
      Sluiting = Stap,
      true
      ;
      sluiting(Stap,F,Sluiting)).

% twee verzamelingen zijn gelijk als het wederzijds verschil de lege verzameling is
set_equals(S1,S2) :-
    set_diff(S1,S2,[]),
    set_diff(S2,S1,[]).

% Verschil tussen twee verzamelingen met eventueel dubbele elementen
set_diff([],_,[]) :- !.
set_diff(In1,[],In1) :- !.
set_diff(In1,In2,Out) :-
    select(E,In2,In2Out),
    select(E,In1,In1Out),
    !,
    set_diff(In1Out,In2Out,Out).

member2(L1,L2) :- intersection(L1,L2,L1).
    
% Maak van een lijst van lijsten één lijst
concat([],[]).
concat(Lists,Out) :- concat(Lists,[],Out).
concat([],Out,Out).
concat([List],Acc,Out) :- concat([List,[]],Acc,Out).
concat([List1,List2|Rest],Acc,Out) :-
    append(List1,List2,Concat),
    append(Concat,Acc,NewAcc),
    concat(Rest,NewAcc,Out).
    
%% Deel 2 %%

alleredundante(F,X) :-
    findall(redundant(Regel,Clause),zoekredundante(F,Regel,Clause),X).

zoekredundante(F,Regel,X) :-
    select(Regel,F,AndereRegels),
    zoek_minimale_redundante(Regel,AndereRegels,X).
    
zoek_minimale_redundante(Regel,AndereRegels,X) :-
    findall(Subset, subseq0(AndereRegels,Subset), Subsets),
    qsort(Subsets, SortedSubsets),
    member(Set,SortedSubsets),
    is_redundant(Regel,Set),
    !,
    length(Set,MinLengte), % het minimaal aantal regels dat redundantie veroorzaakt is gevonden: controller voor elk van de subsets van die lengte of ze redundantie veroorzaken
    gelijke_lengte(MinLengte,SortedSubsets,MinCandidates),
    member(X,MinCandidates),
    is_redundant(Regel,X).

% alle lijsten in de lijst die lengte N hebben
gelijke_lengte(N,Lijst,Uit) :- gelijke_lengte(N,Lijst,[],Uit).
gelijke_lengte(_N,[],Acc,Acc).
gelijke_lengte(N,[L|Rest],Acc,Uit) :-
    length(L,Lengte),
    (N == Lengte ->
        NewAcc = [L | Acc],
        gelijke_lengte(N,Rest,NewAcc,Uit)
    ;
        gelijke_lengte(N,Rest,Acc,Uit)).

% een regel is redundant ten opzichte van de andere regels als de sluiting van de gegeven head
% de body van de regel omvat
is_redundant(A >> B, Regels) :-
    sluiting(A,Regels,Sluiting),
    member2(B,Sluiting).

% alle subsequenties van de gegeven verzameling
subseq0(List, List). % triviaal geval
subseq0(List, Rest) :- subseq1(List, Rest).
subseq1([_|Tail], Rest) :- subseq0(Tail, Rest). % controleert of het tweede argument een echte subsequentie is van het eerste argument
subseq1([Head|Tail], [Head|Rest]) :- subseq1(Tail, Rest).

delete_first_N(N,List,Res) :-
    take(N,List,Smaller),
    set_diff(List,Smaller,Res).

take(0,_,[]).
take(N,[H|T],Res) :-
    NewN is N - 1,
    take(NewN,T,TRes),
    Res = [ H | TRes].

member_with_index(X,N,List) :- member_with_index(X,0,N,List).
member_with_index(X,N,N,[X | _]).
member_with_index(X,Acc,N,[_|List]) :-
    NewAcc is Acc + 1,
    member_with_index(X,NewAcc,N,List).

% sorteer lijsten op lengte
qsort(Lijst,Sorted) :- qsort(Lijst,[],Sorted).
qsort([],L,L).
qsort([Spil|R],Acc,Sorted) :-
    split(Spil,R,Kleiner,Groter),
    qsort(Groter,Acc,NewAcc),
    qsort(Kleiner,[Spil|NewAcc],Sorted).
    
% de comparator is hier de lijstlengte
split(_Spil,[],[],[]).
split(Spil,[X|R],Kleiner,Groter) :-
    length(Spil,SpilLength),
    length(X,XLength),
    SpilLength > XLength, !,
    Kleiner = [X|RestK],
    split(Spil,R,RestK,Groter).
split(Spil,[X|R],Kleiner,Groter) :-
    Groter = [X|RestG],
    split(Spil,R,Kleiner,RestG).