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


/* ========================================================================== */ 
/*                  CONVERT LEAR format (int) to NFOIL format                 */
/*             Dominique BOUTHINON (db@lipn.univ-paris13.fr)                  */
/*  ATTENTION : ne traduit pas completement la theorie du domaine de LEAR     */
/*  les clauses ne sont pas traduites (nFoil est extensionel)                 */
/*             30/09/13                                                       */
/* ========================================================================== */

        /* needed operators */
:- op(900, xfy, <=).           % saturation
:- op(900, xfy, <-).
:- op(900, fx, <-).
:- op(850, xfy, or).
:- op(850, xfy, and).

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

main :-
        halt(1).

goal :-
        get_arguments(File_train, File_bkg, File_foil),
	   convert(File_train, File_bkg, File_foil),
        writeln('end.').
 
get_arguments(File_train, File_bkg, File_foil) :-
        current_prolog_flag(argv, Argv),
        append(_, [--|[File_train, File_bkg, File_foil]], Argv).

/* ==================== 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),

   atom_concat(Lear, '/formated_writing.pl', Format),
   use_module(Format).
   

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

   /* create a file containing positive and negative incomplete examples 
      in a Lear format */
convert(
		   File_train,    % train examples
		   File_bkg,      % background knowledge
		   File_foil	   % name of the ouptut file (with foil ormat)
	   ) :- 

    active_modules,
    writeln('reading files...'),
    consult_data(File_train, File_bkg),
    lear_to_nfoil(File_foil).  
 
	/* get all defined user predicates of the background knowledge */  
lear_to_nfoil(File_foil) :-

   writeln('converting examples...'),
   get_examples(LEx_pos, LEx_neg),
   reset_count(ex),
   convert_examples(LEx_pos, LEx_foil_pos, LPos),
   convert_examples(LEx_neg, LEx_foil_neg, LNeg),
   append(LEx_foil_pos, LEx_foil_neg, LEx_foil),
   flatten(LEx_foil, LEx_foil1),
   sort(LEx_foil1, LEx_foil2),

   build_foil_background(LEx_foil2, LTypes, LRmodes),

   write_foil_data(File_foil, LPos, LNeg, LEx_foil2, LTypes, LRmodes).

  
/* ====================== BUILDING FOIL BACKGROUND ========================== */

build_foil_background(LEx, LTypes, LRmodes_out) :-
   bkg:types_under_oi(LTypes_identifiers),
   bkg:findall(Mode, mode(Mode), LModes),
   add_identifier_to_modes(LModes, LModes1),
   delete_plus_minus_preds(LModes1, LModes2),
   convert_modes_to_types(LModes2, LTypes),
   get_predicates_constants(LEx, LModes2, [ident|LTypes_identifiers], LRmodes),
   set_access(LRmodes, LModes1, LRmodes_out).


	/* give access (+, -) to predicates */ 
set_access([], _LModes, []) :-
   !.

set_access([Pred|LPreds], LModes, LPreds_out) :-
   variabilize_atom(Pred, Pred1),
   member(Pred1, LModes),
   set_access_one_pred(Pred, Pred1, LPreds1),
   set_access(LPreds, LModes, LPreds2),
   append(LPreds1, LPreds2, LPreds_out). 
   

set_access_one_pred(Pred, Pred1, LPreds1) :-
   Pred=..[Functor|LArgs],
   Pred1=..[Functor|LArgs1],
   build_args(LArgs, LArgs1, LArgs2),
   develop_args(LArgs2, LLArgs_out),
   build_predicates(Functor, LLArgs_out, LPreds1).


build_predicates(_Functor, [], []) :-
   !.

build_predicates(Functor, [LArgs|LLArgs], [rmode(Pred)|LPreds1]) :-
   Pred=..[Functor|LArgs],
   build_predicates(Functor, LLArgs, LPreds1).


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

build_args([access|LArgs], [+_Arg1|LArgs1], [[+]|LArgs2]) :-
   !,
   build_args(LArgs, LArgs1, LArgs2).

build_args([access|LArgs], [-_Arg1|LArgs1], [[-]|LArgs2]) :-
   !,
   build_args(LArgs, LArgs1, LArgs2).

build_args([access|LArgs], [_Arg1|LArgs1], [[+,-]|LArgs2]) :-
   !,
   build_args(LArgs, LArgs1, LArgs2).

build_args([Arg|LArgs], [_Arg1|LArgs1], [[Arg]|LArgs2]) :-
   build_args(LArgs, LArgs1, LArgs2).


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

develop_args([LArgs|LLArgs], LLArgs2) :-
   develop_args(LLArgs, LLArgs1),
   add_args(LArgs, LLArgs1, LLArgs2).


add_args([], _LLArgs1, []) :-
   !.

add_args([Arg|LArgs], LLArgs, LLArgs_out) :-
   add_one_arg(Arg, LLArgs, LLArgs1),
   add_args(LArgs, LLArgs, LLArgs2),
   append(LLArgs1, LLArgs2, LLArgs_out).


add_one_arg(_Arg, [], []) :-
   !.

add_one_arg(Arg, [LArgs|LLArgs], [[Arg|LArgs]|LLArgs1]) :-
   add_one_arg(Arg, LLArgs, LLArgs1).

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

add_identifier_to_modes([Mode|LModes], [Mode1|LModes1]) :-
   Mode=..[Functor|LArgs],
   Mode1=..[Functor|[+ident|LArgs]],
   add_identifier_to_modes(LModes, LModes1).
   

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

convert_modes_to_types([Mode|LModes],[type(Type)|LTypes]) :-
   Mode =..[Functor|LArgs_mode], 
   delete_plus_minus_args(LArgs_mode, LArgs_type),
   Type =.. [Functor|LArgs_type],
   convert_modes_to_types(LModes, LTypes).



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

delete_plus_minus_preds([Pred|LPred], [Pred1|LPred1]) :-
   delete_plus_minus_one_pred(Pred, Pred1),
   delete_plus_minus_preds(LPred, LPred1).


delete_plus_minus_one_pred(Pred, Pred1) :-
    Pred =..[Functor|LArgs],
    delete_plus_minus_args(LArgs, LArgs1),
    Pred1 =..[Functor|LArgs1]. 


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

delete_plus_minus_args([+Arg|LArgs], [Arg|LArgs1]) :-
   !,
  delete_plus_minus_args(LArgs, LArgs1).

delete_plus_minus_args([-Arg|LArgs], [Arg|LArgs1]) :-
   !,
  delete_plus_minus_args(LArgs, LArgs1).

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



get_predicates_constants(_LEx, [], _LTypes_identifiers, []) :-
   !.

get_predicates_constants(LEx, [Mode|LModes], LTypes_identifiers, LPred) :-
   get_one_predicate_constants(LEx, Mode, LTypes_identifiers, LPred1),
   get_predicates_constants(LEx, LModes, LTypes_identifiers, LPred2),
   append(LPred1, LPred2, LPred).
   

get_one_predicate_constants(LEx, Mode, LTypes_identifiers, LPred) :-
   build_predicate_template(Mode, Pred),
   findall(Pred, member(Pred, LEx), LInstances), 
   delete_multiple_occurrences(LInstances, Mode, LTypes_identifiers, LPred).


build_predicate_template(Mode, Pred) :-
   Mode =.. [Predicate_name|LArgs], 
   length(LArgs, N),
   functor(Pred, Predicate_name, N).


delete_multiple_occurrences(LInstances, Mode, LTypes_identifiers, LPred) :-
   get_places_identifiers(Mode, LTypes_identifiers, LPlaces),
   replace_identifiers(LInstances, LPlaces, LInstances1),
   sort(LInstances1, LPred).


get_places_identifiers(Mode, LTypes_identifiers, LPlaces) :-
   Mode =..[_Functor|LTypes],
   get_places(LTypes, 1, LTypes_identifiers, LPlaces).


get_places([], _N, _LTypes_identifiers, []) :-
   !.

get_places([Type|LTypes], N, LTypes_identifiers, [N|LPlaces]) :-
   member(Type, LTypes_identifiers),
   !,
   N1 is N+1,
   get_places(LTypes, N1, LTypes_identifiers, LPlaces).


get_places([_Type|LTypes], N, LTypes_identifiers, LPlaces) :-
   N1 is N+1,
   get_places(LTypes, N1, LTypes_identifiers, LPlaces).


replace_identifiers([], _LPlaces, []) :-
   !.

replace_identifiers([Instance|LInstances], LPlaces, [Instance1|LInstances1]) :-
   Instance =.. [Functor|LArgs],
   replace_args(LArgs, LPlaces, 1, LArgs1),
   Instance1 =..[Functor|LArgs1],
   replace_identifiers(LInstances, LPlaces, LInstances1).


replace_args([], _LPlaces, _N, []) :-
   !.


replace_args([_Arg|LArgs], LPlaces, N, [access|LArgs1]) :-
   member(N, LPlaces),
   !,
   N1 is N+1,
   replace_args(LArgs, LPlaces, N1, LArgs1).


replace_args([Arg|LArgs], LPlaces, N, [Arg|LArgs1]) :-
   N1 is N+1,
   replace_args(LArgs, LPlaces, N1, LArgs1).
    

/* ============================== CONSULT DATA ============================== */

consult_data(File_train, File_bkg) :-
   		% consult positive examples
   atom_concat(File_train, '.int', File_train1),
   ex:consult(File_train1),
   atom_concat(File_bkg, '.int_bkg', File_bkg1),
   bkg:consult(File_bkg1).

/* ================== READ EXAMPLES AND BACKGROUND KNOWLEDGE ================ */  
    
get_examples(LPos, LNeg) :-
   ex:findall(pos(N,Ex), pos(N, Ex), LPos),
   ex:findall(neg(N, Ex), neg(N,Ex), LNeg).

/* ============================= CONVERT EXAMPLES =========================== */

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

convert_examples([Ex|LEx], [Ex_foil|LEx_foil], [Ex_dec|LEx_dec]) :-
   convert_one_example(Ex, Ex_foil, Ex_dec),
   convert_examples(LEx, LEx_foil, LEx_dec).


convert_one_example(Ex, L_foil, Dec) :-
   get_count(ex, N),
   Ex =..[Signe, _, L],
   declaration(Signe, N, Dec),
   delete_neg(L, L1),
   convert_list(L1, Signe, N, L_foil).


declaration(pos, N, positive(N)) :-
   !.

declaration(neg, N, negative(N)).


convert_list([], _Signe, _N, []) :-
   !.

convert_list([Atom|LAtoms], Signe, N, [Atom1|LAtoms1]) :-
   Atom =..[Pred|LArgs],
   Atom1 =..[Pred,N |LArgs],
   convert_list(LAtoms, Signe, N, LAtoms1).


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

delete_neg([Atom|LAtoms], LAtoms1) :-
   Atom=..[neg,_],
   !,
   delete_neg(LAtoms, LAtoms1).

delete_neg([Atom|LAtoms], [Atom|LAtoms1]) :-
   delete_neg(LAtoms, LAtoms1).


/* =========================  WRITTING FOIL EXAMPLES ======================== */

write_foil_data(
                     File,
                     
                     LPos, 
                     LNeg,
                     LEx,
                     LTypes,
                     LModes
                     ) :- 

  atom_concat(File, '.pl', File1),
  open(File1, write, Stream),

  
  fwrite_point_ln(Stream, classes(positive, negative)),
  nl(Stream),

  fwrite_point_ln(Stream, type(class(ident))),
  fwriteln_list(Stream, LTypes),
  nl(Stream),

  fwriteln_list(Stream, LModes),
  nl(Stream),

  fwriteln_list(Stream, LPos),
  nl(Stream),
  
  fwriteln_list(Stream, LNeg),
  nl(Stream),

  fwriteln_list(Stream, LEx),
  nl(Stream),

  close(Stream).

/* ============================== END OF LISTING ============================ */   
   
