#! /usr/bin/swipl
% (home + travail)

% #! /usr/local/swipl/bin/swipl
% (magi)

/* ========================================================================== */ 
/*                              AMBIGUITY GENERATOR                           */
/*             generate ambiguous examples from complete examples             */
/*                 by removing facts at random                                */
/*                 according to a i.i draw                                    */
/* ========================================================================== */


:- set_prolog_flag(verbose, silent).
												% stacks
:- set_prolog_stack(local,  limit(10**9)).  	% 1 Go
:- set_prolog_stack(global, limit(10**9)).	
:- set_prolog_stack(trail,  limit(10**9)).

:- initialization goal.

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

goal :-
        get_arguments(File_in, File_out, Percent, Factor, Double),
	   create_ambiguous_examples(File_in, File_out, Percent, Factor, Double),
	   halt(0).
 
get_arguments(File_in, File_out, Percent, Factor, Double) :-
        current_prolog_flag(argv, Argv),
        append(_, [File_in, File_out, Percent1, Factor1, Double], Argv),
	   atom_number(Percent1, Percent),
	   atom_number(Factor1, Factor).


   	  /* create a file containing positive and negative ambiguous examples */
create_ambiguous_examples(
       File_in,   % file containing intensional complete examples
       File_out,  % result file containing intensional ambiguous examples
       Percent,   % percentage of ambiguity
       Factor,    % one creates M*N ambiguous examples from N complete examples
	  Double	   % 'double' in case of double representation
                         ) :- 

   import_modules,
   init_randomize,

   Proba is Percent/100.0,
   Proba_to_be_kept is 1.0 - Proba,
   
   writeln('making examples ambiguous...'),
   create_ambiguity(File_in, File_out, Proba_to_be_kept, Factor, Double),
   writeln('finished').


import_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, '/randomize.pl', Random),
   use_module(Random),

   atom_concat(Lear, '/intentional_data.pl', Read_write),
   use_module(Read_write).

/* ========================= CREATING AMBIGUOUS EXAMPLES ==================== */  

create_ambiguity(File_in, File_out, Proba, Factor, Double) :-

   read_intentional_examples(ex, File_in, LPos, LNeg),

   atom_concat(File_out, '.int', File_out1),
   open(File_out1, write, Stream),

   fwrite_ln(Stream, ':- style_check(-discontiguous).'),
   nl(Stream),
   
   reset_count(nb_examples),
   length(LPos, N_pos),
   K_pos is N_pos * Factor,       % # of positive ambigous examples to create
   deal_with_examples(pos, K_pos, LPos, Proba, Double, Stream),
   
   nl(Stream),
   nl(Stream),
   
   reset_count(nb_examples),
   length(LNeg, N_neg),
   K_neg is N_neg * Factor,        % # of negative ambigous examples to create
   deal_with_examples(neg, K_neg, LNeg, Proba, Double, Stream),
  
   close(Stream).
   

	/* draw an example Ex in Lex and discard some atoms of Ex accordin to
	   Proba */
deal_with_examples(Signe, K, Lex, Proba, Double, Stream) :-
   length(Lex, N),
   n_times(K),
   draw_an_example(N, Lex, (Ex, Domains, Target)),
   create_an_ambiguous_example(Ex, Proba, Double, Ambiguous_ex),
   get_count(nb_examples, Nex),
   write_intentional_example_domain_target((Ambiguous_ex, Domains, Target),
                                           Signe, Nex, Stream),
   fail.
   
deal_with_examples(_Signe, _K, _Lex, _Proba, _Double, _Stream). 


	/* draw an example in Lex */
draw_an_example(N, Lex, Ex) :-
   draw_integer(1, N, Index),
   nth1(Index, Lex, Ex).
   

   /* write all targets */
write_numbered_list([], _Pred, _N, _Stream) :-
   !.
   
write_numbered_list([Args|LArgs], Pred, N, Stream) :-
    Atom=..[Pred|[N,Args]],
    fwrite_point_ln(Stream, Atom),
    N1 is N+1,
    write_numbered_list(LArgs, Pred, N1, Stream).
    

/* ====================== SELECTING ATOMS TO BE DISCARDED =================== */

	/* create an ambiguous example from one complete example discarding
	   drawn literals */
	   
create_an_ambiguous_example([], _Proba, _Double, []) :-
   !.
   	   
						% one keeps Literal and its associated Literal
create_an_ambiguous_example(
                            [Literal|Literals], 
                            Proba_to_be_kept, 
                            Double,
                            Ambiguous_ex
                           ) :-                       
   draw_float(1.0, P), 
   P =< Proba_to_be_kept,
   !, 
   keep_associated_literal(Double, Literal, Literals, Literals1, Keep),                                                    
   create_an_ambiguous_example(Literals1, Proba_to_be_kept, Double, Ambiguous_ex1),
   append(Keep, Ambiguous_ex1, Ambiguous_ex).                          
   
						% one discards Literal and its associated Literal
create_an_ambiguous_example(
                            [Literal|Literals], 
                            Proba_to_be_kept, 
                            Double,
                            Ambiguous_ex
                           ) :-    
   discard_associated_literal(Double, Literal, Literals, Literals1),                    
   create_an_ambiguous_example(Literals1, Proba_to_be_kept, Double, Ambiguous_ex).                             



	/* in case of double representation get the associated literal */
keep_associated_literal(double, Literal, Literals, Literals1, 
                        [Literal, Associated_literal]) :-
     !,
    discard_associated_literal(double, Literal, Literals, Literals1),                        
    associated_literal(Literal, Associated_literal).

							% not in double representation
keep_associated_literal(_, Literal, Literals, Literals, [Literal]).



	/* in case of double representation discard the associated
        positive or negative literal */
discard_associated_literal(double, Literal, Literals, Literals1) :-
     !,
     associated_literal(Literal, Associated_literal),                        
	select(Associated_literal, Literals, Literals1).

							% not in double representation
discard_associated_literal(_, _Literal, Literals, Literals).


	/* build the associated literal */
associated_literal(neg(Atom), Negated_atom) :-
   !,
   negated_atom(Atom, Negated_atom).

associated_literal(Atom, neg(Negated_atom)) :-
   negated_atom(Atom, Negated_atom).


negated_atom(Atom, Negated_atom) :-
   Atom=..[Predicate|LArgs],
   negation_predicate(Predicate, Negated_predicate),
   Negated_atom=..[Negated_predicate|LArgs].


	/* build the negation of an atom */
negation_predicate(Not_predicate, Predicate) :-
	atom_concat('not_', Predicate, Not_predicate),
	!.

negation_predicate(Predicate, Not_predicate) :-
	atom_concat('not_', Predicate, Not_predicate).


	/* create a set of ambiguous examples from one complete example */
make_ambiguity(LAtoms, Proba, LExamples) :-
   length(LAtoms, N),
   K is round(N*Proba),			% K is the number of atoms to discard
   check_K(N, K, K1),
   K2 is N-K1,
   combinations(LAtoms, K2, LExamples).
   
   
   /* check that K is at most N */   
check_K(N, K, K) :-
   K =< N,
   !.
   
check_K(N, _K, N).   
   
/* ============================== END OF LISTING ============================ */   

