
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% This is the code for the Trial Generator component of ASE-Progol.

% The code outputs a file called trials.pl which contains
% trial/1 facts, where the argument is a ground unit clause
% representing an trial.

% The code consults a file which contains a domain-specific SLP
% definition of the predicate sample_trials(Quantity,
% List_of_trials, Trial_selection_method).  The first term is the
% size of the sample of trials generated by the SLP. NB This
% sample may contain duplicates. Thus the sample size may be greater
% than the cardinality of the set of trials output by the
% program.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

:- set(r,10000)?
:- set(h,10000)?

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Selects the first trial that the robot will perform. 20 trials are
%% generated using the SLP. Normally the cheapest of these is then
%% chosen to be the first trial. However if ASE-Progol has been
%% instructed to select trials at random then one of the 20 trials is
%% picked at random.
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

generate_first_trial(SLP_file, random, Trials_file):-
	consult(SLP_file),
	sample_trials(20, [H|_], Trial_selection_method),
	tell(Trials_file), 
	wrap_list_elements([H]),
	told.

generate_first_trial(SLP_file, Trial_selection_method, Trials_file):-
	(Trial_selection_method = normal; Trial_selection_method = naive),
	consult(SLP_file),
	sample_trials(20, L, Trial_selection_method),
	get_cheapest_trial(L, Cheapest_trial),
	tell(Trials_file), 
	wrap_list_elements([Cheapest_trial]),
	told.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Generates a set of candidate trials.
%% 
%% This code ensuress that the list of candidate trials does not
%% include any trials that have already been performed.
%% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

generate_trials(SLP_file, Prev_trials_file, Trial_selection_method, Trials_file, Quantity):-
	consult(SLP_file),
	consult(Prev_trials_file),
	sample_trials(Quantity, L, Trial_selection_method),
	remove_dups(L, List_of_trial),
	setof(Prev_trial, example(_, Prev_trial, Class), L_prev_trials),
	set_difference(List_of_trial, L_prev_trials, L_candidate_trials),
	tell(Trials_file), 
	wrap_list_elements(L_candidate_trials),
	told.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% ASE-Progol simply chooses the cheapest trial when the number of
%% hypotheses < 2, or when ASE-Progol has been instructed to naively
%% select the cheapest trial from the set of candidate trials.
%% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

select_cheapest_trial(SLP_file, Trials_file, Current_trial_file):-
	consult(SLP_file),
	consult(Trials_file),
	setof(Trial, trial(Trial), L),
	get_cheapest_trial(L, Cheapest_trial),
	tell(Current_trial_file),
	write('trial('),
	write(Cheapest_trial),
	write(').'),
	told.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Assumes that the SLP_file consults the static_know and thus that
%% cost/2 is defined.

get_cheapest_trial(L, Cheapest_trial):-
	get_cost_of_trials(L),
	setof(Cost, cost_of_candidate_trial(Trial, Cost), List_of_costs),
	qsort(List_of_costs, [Cheapest_cost | _]),
	cost_of_candidate_trial(Cheapest_trial, Cheapest_cost).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

get_cost_of_trials([]).

get_cost_of_trials([H|T]):-
	cost(H, H_cost),
	asserta(cost_of_candidate_trial(H, H_cost)),
	get_cost_of_trials(T).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% set_difference
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

set_difference(X, [], X).

set_difference(A, [H | T], Diff):-
 delete(H, A, B),
 set_difference(B, T, Diff).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% This version of remove_dups retains original order of list but is
% inefficient

remove_dups([], []).

remove_dups([X|Xs], [X|Ys]):-
	delete(X, Xs, Xs1),
	remove_dups(Xs1,  Ys).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% delete(X, Y, Z) deletes all occurrences of X from Y to give Z.

delete(_, [], []).

delete(H, [H|T], R):-
	delete(H, T, R).

delete(A, [H|T], [H|R]):-
	not(A = H),
	delete(A, T, R).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

wrap_list_elements([]).
wrap_list_elements([Head | Tail]):-
	write('trial('),
	write(Head),
	write(').'),
	nl,
	wrap_list_elements(Tail).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% qsort(List1, List2)
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

qsort( [], [] ).

qsort( [H | T], Slist ):-
    partition( H, T, L1, L2 ),
    qsort( L1, Slist1 ),
    qsort( L2, Slist2 ),
    append( Slist1, [H | Slist2], Slist ).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% partition(Divider, List1, List2, List3)
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

partition(Divider, [H | T], [H | S1], S2):-
    H @=< Divider,
    partition(Divider, T, S1, S2).

partition(Divider, [H | T], S1, [H | S2]):-
    H @> Divider,
    partition(Divider, T, S1, S2).

partition(_, [], [], []).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

append([],L,L).
append([H|T],L,[H|Z]) :- append(T,L,Z).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

