#! /usr/bin/swipl -q -G1g -L1g -T1g -t main -s
% (home)

% #! /usr/local/bin/lib/swipl-5.11.34/bin/x86_64-linux/swipl -q -G1g -L1g -T1g -t main -s
% (travail)


/* ========================================================================== */ 
/*                  CONVERT ALEPH FORMAT TO LEAR format (int)                 */
/*             (a key must not be completly included in arguments of facts)   */
/*             (Attention à la notion de Keys associés)                       */
/* ========================================================================== */

main :-
        catch(goal, E, (print_message(error, E), fail)),
        halt.

main :-
        halt(1).

goal :-
        get_arguments(File_train, File_bkg, File_lear),
	     convert(File_train, File_bkg, File_lear).
 
get_arguments(File_train, File_bkg, File_lear) :-
        current_prolog_flag(argv, Argv),
        append(_, [--|[File_train, File_bkg, File_lear]], Argv).

/* =========================== TRANSLATION OF EXAMPLES ====================== */

   /* create a file containing positive and negative incomplete examples 
      in a tilde format */
convert(
		   File_train,    % train examples
		   File_bkg, 	   % background knowledge
		   File_lear		% name of the ouptut file (with lear format)
	   ) :- 
    active_modules,
    consult_data(File_train, File_bkg),
    aleph_to_lear(File_lear).  
 
	/* get all defined user predicates of the background knowledge */
   
aleph_to_lear(File_lear) :-
   get_modes(LModes),
   get_examples(LModes, LPos, LNeg),
   get_types(LModes, LTypes1),
   sort(LTypes1, LTypes),				% mandatory
   write_lea_examples(File_lear, LPos, LNeg, LModes, LTypes).
  
/* ================== READ EXAMPLES AND BACKGROUND KNOWLEDGE ================ */  
    
get_examples(LModes, LPos, LNeg) :-
   get_head_concept(Concept),
   build_examples(LModes, Concept, pos, LPos),
   build_examples(LModes, Concept, neg, LNeg).  


	/* get head examples and predicates used in hypotheses */
get_head_concept(Head_concept) :-
  bkg:modeh(_, Concept),
  functor(Concept, Name, Arity),
  functor(Head_concept, Name, Arity).


	/* build examples from heads and facts using LPredicates */
build_examples(LModes, Head_ex, Label, LEx) :-
   findall(Head_ex, Label:Head_ex, LHead_ex),
   gtrace,
   get_examples_properties(LModes, LHead_ex, LEx).


	/* get in background knowledge, the facts (properties) associated 
        with given heads of concepts */
get_examples_properties(_LModes, [], []) :-
   !.

get_examples_properties(LModes, [Head_ex|LHead_ex], [[Head_ex|Ex]|LEx]) :-
   gtrace,
   get_key_current_example(Head_ex, Key),
               % A Key is a list of (type, ident) unique for every example
			% in case identifiers are compound we must consider other
               % identifiers
   get_list_keys(Key, LKey),	

			% in this version we consider a Key as a unique pair (type,value)
   flatten_keys(LKey, LKey1),
  
			% get in Ex1, all facts that contains in their arguments
               % a PART OF key in LKey
   get_properties_example_keys(LKey1, LModes, Ex1),	
   sort(Ex1, Ex2),


		
			% LTypes contains types used for identifying objects in 
               % the examples
   bkg:types_identifiers(LTypes),	   
   build_associated_keys(Ex2, LModes, LTypes, LAssociated_keys),

   flatten_keys(LAssociated_keys, LAssociated_keys1),
  
			% LTypes contains types (other than those in LKey)
               % describing objects. These types are linked with type of LKey	
   get_properties_example_keys(LAssociated_keys1, LModes, Ex3),

   append(Ex2, Ex3, Ex4),
   sort(Ex4, Ex),


   get_examples_properties(LModes, LHead_ex, LEx).


flatten_keys(LKey, LKey_out) :-
 flatten(LKey, LKey1),
 sort(LKey1, LKey_out).



	/* build keys associated with Key identifying examples */
build_associated_keys(Ex, LModes, LTypes, LKeys) :-
   select_modes(Ex, LModes, LModes1),
   build_keys_facts(Ex, LModes1, LTypes, LKeys).


build_keys_facts([], [], _LTypes, []) :-
   !.

build_keys_facts([Fact|LFacts], [Mode|LModes], LTypes, LKeys) :-
   build_keys_one_fact(Fact, Mode, LTypes, LKeys1),
   build_keys_facts(LFacts, LModes, LTypes, LKeys2),
   append(LKeys1, LKeys2, LKeys).

   
build_keys_one_fact(Fact, Mode, LTypes, LKeys) :-
   Fact=..[Pred|LArgs_fact],
   Mode=..[Pred|LArgs_mode],
   associate_types_values(LArgs_fact, LArgs_mode, LTypes, LKeys).


associate_types_values([], [], _LTypes, []) :-
   !.

associate_types_values([Value|LValues], [Arg_type|LArgs_types], 
                        LTypes, [[(Arg_type, Value)]|LKeys]) :-
   member(Arg_type, LTypes),
   !,
   associate_types_values(LValues, LArgs_types, LTypes, LKeys).

associate_types_values([_|LValues], [_|LArgs_types], LTypes, LKeys) :-
   associate_types_values(LValues, LArgs_types, LTypes, LKeys).
    

	/* select the modes in LModes that describe the facts in LFacts */
select_modes([], _LModes, []) :-
   !.

select_modes([Fact|LFacts], LModes, [Mode|LModes1]) :-
   functor(Fact, Pred, Arity),
   functor(Mode, Pred, Arity),
   member(Mode, LModes),
   !,
   select_modes(LFacts, LModes, LModes1).

select_modes([_Fact|LFacts], LModes, LModes1) :-
   select_modes(LFacts, LModes, LModes1).
   
/* ======================== GET PROPERTIES OF EXAMPLES ====================== */

get_properties_example_keys([], _, []) :-
   !.

get_properties_example_keys([Key|LKey], LModes,  Ex) :-
   get_properties_example(LModes, Key, Ex1),
   get_properties_example_keys(LKey, LModes,  Ex2),
   append(Ex1, Ex2, Ex).


	/* get all properties (facts) having a part of Key as parameters */
get_properties_example([], _Key, []) :-
   !.

get_properties_example([Mode|LModes], Key, Ex) :-
   find_instances_key(Mode, Key, LFacts1),
   get_properties_example(LModes, Key, LFacts2),
   append(LFacts1, LFacts2, Ex).
    

	/* find instances of Predicate that contains a part of Key */
find_instances_key(Mode, Key, LFacts) :-
   Mode=..[_|LTypes],
   build_predicate_instances(Key, [Mode], LModes),
   replace_types_by_variables(LModes, LTypes, LModes1),
   find_all_instances(LModes1, LFacts).


	/* find in bkg all facts having patterns in LModes */
find_all_instances([], []) :-
   !.

find_all_instances([Mode|LModes], LFacts) :-
   findall(Mode, bkg:Mode, LFacts1),
   find_all_instances(LModes, LFacts2),
   append(LFacts1, LFacts2, LFacts).


	/* replace all types of LTypes in LModes by variables */
replace_types_by_variables([], _LTypes, []) :-
   !.

replace_types_by_variables([Mode|LModes], LTypes, [Mode1|LModes1]) :-
   Mode=..[Functor|LArgs_mode],
   change_types(LArgs_mode, LTypes, LArgs_mode1),
   Mode1=..[Functor|LArgs_mode1],
	replace_types_by_variables(LModes, LTypes, LModes1).

change_types([], _LTypes, []) :-
   !.

change_types([Arg|LArgs], LTypes, [_X|LArgs1]) :-
   member(Arg, LTypes),
   !,
   change_types(LArgs, LTypes, LArgs1).

change_types([Arg|LArgs], LTypes, [Arg|LArgs1]) :-
    change_types(LArgs, LTypes, LArgs1).
   

	/* returns all combinations by replacing a type of each predicate with 
      a value of the same type of Key */

build_predicate_instances((Type,Value), LPredicates, LPredicates1) :-
   replace_one_parameter_predicates(LPredicates, Type, Value, LPredicates1).
  
   
replace_one_parameter_predicates([], _Type, _Value, []) :-
   !.

replace_one_parameter_predicates([Predicate|LPredicates], Type, Value, LP) :-
   replace_one_paremeter_one_predicate(Predicate, Type, Value, LP1),
   replace_one_parameter_predicates(LPredicates, Type, Value, LP2),
   append(LP1, LP2, LP).


	/* return all combinations by replacing a parameter Type of Predicate, 
      with Value */
replace_one_paremeter_one_predicate(Predicate, Type, Value, LPredicates) :-
   Predicate=..[Pred|LArgs],
   findall(LArgs1, replace_one_element(LArgs, Type, Value, LArgs1), LLArgs),
   make_predicates(LLArgs, Pred, LPredicates).


	/* return all combinations by replace one value Type of LArgs with Value */
replace_one_element([], _Type, _Value, []) :-
   !,
   fail.

replace_one_element([Type|LArgs], Type, Value, [Value|LArgs]).
        % ne pas mettre de cut

replace_one_element([Arg|LArgs], Type, Value, [Arg|LArgs1]) :-
   replace_one_element(LArgs, Type, Value, LArgs1).
   

 	/* build a list of predicates from list of arguments */
make_predicates([], _Pred, []) :-
   !.

make_predicates([Args|LArgs], Pred, [Pred1|LPred1]) :-
   Pred1=..[Pred|Args],
   make_predicates(LArgs, Pred, LPred1).     
   
/* ============================ MANAGE KEY OF EXAMPLES ====================== */

	/* get a list of idents, when Ident is a compound term */
get_list_keys(Key, [Key]) :-
   not_compound_element(Key),
   !.

get_list_keys(Key, [Key|LKey]) :-
   decompound(Key, Key1),
   get_list_keys(Key1, LKey).


	/* break down arguments elements of L */
decompound([], []) :-
   !.

decompound([(Type,Value)|L], [(Type, Value1)|L1]) :-
   Value=..[_|[Value1]],
   decompound(L, L1).
   
   
		/* check whether L contains or not a compound element */
not_compound_element([]) :-
   !.

not_compound_element([(_Type, Value)|_]) :-
   compound(Value),
   !,
   fail.

not_compound_element([_|L]) :-
   not_compound_element(L).
  

	/* get the list of (type, identifier) associated with current example */
get_key_current_example(Head_ex, Key) :-
   bkg:modeh(_, Mode),
   Mode=..[_|LArgs_mode],
   Head_ex=..[_|LArgs_ex],
   get_key_identifiers(LArgs_mode, LArgs_ex, Key).


	/* get the Key */
get_key_identifiers([], [], []) :-
   !.

get_key_identifiers([+Type|LTypes], [Value|LValues], [(Type,Value)|Key]) :-
   !,
   get_key_identifiers(LTypes, LValues, Key).

get_key_identifiers([_|LTypes], [_|LValues], Key) :-
   get_key_identifiers(LTypes, LValues, Key). 


/* ========================================================================== */
  

 	/* gather all modes in a list */
get_modes(LModes) :-
   findall(Mode, bkg:modeb(_, Mode), LModes1),
   discard_plus_minus(LModes1, LModes).

discard_plus_minus([], []) :-
   !.

discard_plus_minus([Mode|LModes], [Mode1|LModes1]) :-
   discard_plus_minus_one_mode(Mode, Mode1),
   discard_plus_minus(LModes, LModes1).


discard_plus_minus_one_mode(Mode, Mode1) :-
   Mode=..[Pred|LArgs],
   discard_plus_minus_args(LArgs, LArgs1),
   Mode1=..[Pred|LArgs1].

discard_plus_minus_args([], []) :-
   !.

discard_plus_minus_args([Arg|LArgs], [Arg1|LArgs1]) :-
   discard_plus_minus_one_arg(Arg, Arg1),
   discard_plus_minus_args(LArgs, LArgs1).

discard_plus_minus_one_arg(+Arg, Arg) :-
   !.

discard_plus_minus_one_arg(-Arg, Arg) :-
   !.

discard_plus_minus_one_arg(Arg, Arg).


	/* gather all types present in LModes in a list */
get_types([], []) :-
   !.

get_types([Mode|LModes], LTypes) :-
   Mode=..[_|LTypes1],
   get_types(LModes, LTypes2),
   append(LTypes1, LTypes2, LTypes).
   
/* ==============================  WRITTING EXAMPLES ======================== */

write_lea_examples(
                     File,
                     LPos, 
                     LNeg,
                     LModes,
				 LTypes
                     ) :- 
   atom_concat(File, '.int', File1),
   open(File1, write, Stream),

   write(Stream, ':- style_check(-discontiguous).'), 
   nl(Stream),

   reset_count(nb_examples),
   
   write_examples(pos, LPos, LModes, LTypes, Stream),
   nl(Stream),
   nl(Stream),
   write_examples(neg, LNeg, LModes, LTypes, Stream),
   
   close(Stream).


write_examples(_Label, [], _LModes, _LTypes, _Stream) :-
   !.

write_examples(Label, [Ex|Lex], LModes, LTypes, Stream) :-
   write_one_example(Label, Ex, LModes, LTypes, Stream),
   write_examples(Label, Lex, LModes, LTypes, Stream).


/* write the current example in lea format */ 
write_one_example(Label, [Head|Ex], LModes, LTypes, Stream) :-
  get_count(nb_examples, N),
  fwrite(Stream, Label),
  write(Stream, '('),
  write(Stream, N),
  write(Stream,','),
  nl(Stream),
  fwrite_list(Stream, Ex),
  fwrite_point_ln(Stream, ')'),
  nl(Stream),
  fwrite_point_ln(Stream, target(N, Head)),
  write_domains(Stream, N, LModes, LTypes, Ex),
  nl(Stream),
  nl(Stream).
  
  
write_domains(Stream, N, LModes, LTypes, Ex) :-
  get_domains(LTypes, LModes, Ex, LDomains),
  write(Stream, 'domains('),
  write(Stream, N),
  write(Stream, ','),
  fwrite_list(Stream, LDomains),
  write(Stream, ').').
  

	/* get values of types in the example Ex */  
get_domains([], _LModes, _Ex, []) :-
   !.
	
get_domains([Type|LTypes], LModes, Ex, [Domain|LDomains]) :-
   get_values_type(Type, LModes, Ex, LValues),
   sort(LValues, LValues1),
   not_empty(LValues1),
   !,
   Domain=..[Type|[LValues1]],
   get_domains(LTypes, LModes, Ex, LDomains).
   
get_domains([_Type|LTypes], LModes, Ex, LDomains) :-
    get_domains(LTypes, LModes, Ex, LDomains).
         

	/* get all values of the given type in the example Ex */
get_values_type(_Type, [], _Ex, []) :-
   !.
	
get_values_type(Type, [Mode|LModes], Ex, LValues) :-
   Mode=..[Pred|LArgs],
   get_indices(1, Type, LArgs, LIndices),
   length(LArgs, N),
   functor(Mode1, Pred, N), 
   get_values(LIndices, Mode1, Ex, LValues1),
   get_values_type(Type, LModes, Ex, LValues2),
   append(LValues1, LValues2, LValues).
   
   
	/* get indices in list L of occurrences of X */  
get_indices(_N, _X, [], []) :-
   !.
	
get_indices(N, X, [X|L], [N|LIndices]) :-
   !,
   N1 is N+1,
   get_indices(N1, X, L, LIndices).
   
get_indices(N, X, [_|L], LIndices) :-
   N1 is N+1,
   get_indices(N1, X, L, LIndices).
   
	/* get all values of arguments placed in positions given by LIndices */  
get_values([], _Mode, _Ex, []) :-
   !.
	
get_values([Indice|LIndices], Mode, Ex, LValues) :-
   findall(Value, (member(Mode, Ex), arg(Indice, Mode, Value)), LValues1),
   get_values(LIndices, Mode, Ex, LValues2),
   append(LValues1, LValues2, LValues).
     
write_atoms(_Stream, []) :-
   !.
   
write_atoms(Stream, [A|L]) :-   
  fwrite_point_ln(Stream, A),
  write_atoms(Stream, L).
  

/* ==================== ACTIVE MODULES and CONSULT DATA ===================== */
 
active_modules :-
   getenv('LEAR_DIR', Lear),
   atom_concat(Lear, '/file.pl', File),
   use_module(File),

   atom_concat(Lear, '/counter.pl', Counter),
   use_module(Counter),  

   atom_concat(Lear, '/list.pl', List),
   use_module(List),
   
   atom_concat(Lear, '/term.pl', Term),
   use_module(Term).

consult_data(File_train, File_bkg) :-
   		% consult positive examples
   atom_concat(File_train, '.f', File_train_pos),
   pos:consult(File_train_pos),
   
		% consult negative examples
   atom_concat(File_train, '.n', File_train_neg),
   neg:consult(File_train_neg),
  
		% consult background knowledge
   atom_concat(File_bkg, '.b', File_bkg1),
   bkg:consult(File_bkg1).

/* ============================== SATURATION ================================ */    

	/* saturate all clauses of the background knowledge on examples */
saturate :-
     bkg:saturation(LP),
     bkg:run_predicates(LP).

	/* execute all predicates of the list */
run_predicates([]) :-
   !.

run_predicates([P|LP]) :-
     copy_term(P, P1),
	  findall(P1, train:P1, LP1),
     assert_facts(LP1),
     run_predicates(LP).


assert_facts([]) :-
   !.

assert_facts([F|LF]) :-
   bkg:assert(F),
   assert_facts(LF) .
     
/* ============================== END OF LISTING ============================ */   
   
