%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Inlämningsuppgift 4 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

:- use_module(library(lists)).
:- [res_inf].

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% uppgift 1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	%% classes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

classes(Es, Cs) :-
	countClasses(Es, Cs2),
	sortClasses(Cs2, Cs),!.


countClasses([],[]).

countClasses([(Class,_)|Rest], Cs) :-
	countClasses(Rest, Cs2),!,
	updateCs(Class, Cs2, Cs).


updateCs(Class, Cs2, Cs) :-
	append(L1, [(Class, N)|Rest], Cs2),
	N2 is N + 1,
	append(L1, [(Class, N2)|Rest], Cs).

updateCs(Class, Cs2, [(Class, 1)| Cs2]).

updateCs(Class, [], [(Class, 1)]).


sortClasses(List, Sorted) :-
	swap(List, List1),!,
	sortClasses(List1, Sorted).

sortClasses(Sorted, Sorted).

swap([X,Y|Rest],[Y,X|Rest]) :-
	less(X,Y).

swap([Z|Rest],[Z|Rest1]) :-
	swap(Rest, Rest1).

less((_,G),(_,S)) :-
	G < S.

	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	%% best_attribute %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

best_attribute(ExLst, AttLst, BestAtt, AttRest, ValExLst):-
	best_so_far(ExLst, AttLst, BestAtt, _, ValExLst),
	append(Start,[BestAtt|End], AttLst),
	append(Start, End, AttRest).


best_so_far(_, [], _, 2, _).

best_so_far(ExLst, [Att|Rest], BestAtt, BestVal, ValExLst):-	
	best_so_far(ExLst, Rest, BestAtt1, BestVal1, ValExLst1),
	make_valExLst(ExLst, Att, ValExLst2, NumOfEx),
	residual_information(ValExLst2, NumOfEx, BestVal2),
	choose_best(Att, BestVal2, ValExLst2, BestAtt1, BestVal1, ValExLst1, BestAtt, BestVal, ValExLst).

choose_best(A, V1, VEL, _, V2, _, A, V1, VEL) :-
	V1 < V2,!.
choose_best(_, _, _, A, V, VEL, A, V, VEL).


% make_valExLst(+Exempellista, +Attribut, -VärdeSubexempellista, -Antal_Exempel_I_Värde/Subexempellistan)
make_valExLst(ExLst, Attribute, VEL, NumOfEx) :-
	make_valExLst(ExLst, Attribute, VEL),
	count_ex(VEL, NumOfEx).

% make_valExLst(+Exempellista, +Attribut, -VärdeSubexempellista)
make_valExLst([], Attribute, VEL) :-
	attribute(Attribute, ValueLst),
	bagof((Value, []), get_element(ValueLst, Value), VEL).

make_valExLst([(Class, AttValLst)|Rest], Attribute, VEL) :-
	make_valExLst(Rest, Attribute, VEL1),
						% Vilket värde har Attributet i aktuellt exempel
	append(Start, [(Attribute, Value)|End], AttValLst), 
						% I vilket värde/subexempellistapar skall aktuellt
						% exempel sättas sättas in
	append(Start2,[(Value,SubExLst)|End2],VEL1),         
						% Sätt in aktuellt exempel på denna plats
	append(Start2,[(Value,[(Class, AttValLst)|SubExLst])|End2], VEL).

get_element([First|Rest], First).
get_element([First|Rest], Element) :-
	get_element(Rest, Element).

count_ex([], 0).
count_ex([(_,Lst)|Rest], N1) :-
	count_ex(Rest, N2),
	length(Lst, N3),
	N1 is N2 + N3.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% uppgift 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	%% classify %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

classify(Ex, (Attribute,Rest), Class) :-
	append(_,[(Attribute, Value)|_], Ex), % Letar reda på exemplets värde för första attributet i trädet.
	classify(Ex, Value, Rest, Class).

classify(_, Value, Tree, Class) :-
	append(_,[(Value, class(Class))|_], Tree).

classify(Ex, Value, Tree, Class) :-
	append(_, [(Value, Attribute, Rest)|_], Tree),
	classify(Ex, (Attribute, Rest), Class).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% uppgift 3 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	%% train, tränar trädet %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

train:-
	[shuttle_train],
	bagof((Class,AVLst), example(Class,AVLst),ExLst),
	decision_tree(ExLst, [stability,error,sign,wind,magnitude,visibility], neg, T),
	assert(tree(T)).
%	remove(example(_,_)). % år inte dynamic att funka :(

remove(X) :-
	retract(X),
	fail.

	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	%% Classify_lst, testar träningsmängden %%%%%%%%%%%%%%%%%%%%
	%% resultat: 163 av 178 exempel är korrekt klassificerade %%
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% snabbis, laddar in tränings och testmängden, tränar trädet och testar exemplen
qtest(Corect, Total) :-
	shuttle_test,
	train,
	test(Corect,Total).

% Läser in träningsmängden
shuttle_test:-
	[shuttle_test],
	bagof((Class,AVLst), texample(Class,AVLst),ExLst),
	assert(testLst(ExLst)).
%	remove(texample(_,_)). % år inte dynamic att funka :(

% resultat: 163 av 178 exempel är korrekt klassificerade
%kräver att man först kört shuttle_test och train
% test(-AntalKorektaKlassificeringar, -TotaltAntalExempel)
test(Corect, Total) :-
	testLst(ExLst),
	tree(Tree),
	classify_lst(ExLst,Tree,Corect,Total),!.

classify_lst([],_,0,0).

classify_lst([(Class,AVLst)|Rest], Tree, Corect, Total) :-
	classify_lst(Rest, Tree, Corect2, Total2),
	classify(AVLst, Tree, Class2),
	same_class(Class, Class2, Int),
	Total is Total2 + 1,
	Corect is Corect2 + Int.

same_class(Class, Class, 1) :- !.
same_class(_,_,0).



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% copycat %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

decision_tree([],_,D,class(D)) :- !.
decision_tree(Es,_,_,class(C)) :-
	classes(Es,[(C,_)]), !.
decision_tree(Es,[],_,class(C)):- !,
	classes(Es,[(C,_)|_]).
decision_tree(Es,As,_,(A,Trees)) :-
        best_attribute(Es,As,A,AsRest,VEs),
	classes(Es,[(D,_)|_]),
        make_trees(VEs,AsRest,D,Trees).

make_trees([],_,_,[]).
make_trees([(V,Es)|VEs],AsRest,D,[(V,T)|Trees]) :-
        decision_tree(Es, AsRest, D, T),
        make_trees(VEs, AsRest, D, Trees).

attribute(stability,[stab,xstab]).
attribute(error,[xl_error,lx_error,mm_error,ss_error]).
attribute(sign,[pp_sign,nn_sign]).
attribute(wind,[head_wind,tail_wind]).
attribute(magnitude,[low,medium,strong,out_of_range]).
attribute(visibility,[yes,no]).


%% lazy %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
l:-[inl4].
