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

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

/* ========================================================================== */
/*                                                                            */
/*				Create intentional positive and examples			   */
/*				by drawing interpretations a given first order language.  */
/*				Every interpretation satisfying a given background 	   */
/*				knowledge is labelled positive, otherwise negative.       */
/*                  (in this version the user gives the number of examples    */
/*                   he wants without distinguish positive examples from      */
/*                   negative ones)                                           */
/* ========================================================================== */
/*              
 				One uses the background knowledge format of LEAR 			  
                with two IMPORTANT additional atoms :					      
                domains([
                         type1([value11, value12, ..]),                     
                         type2[value21, value22,...)],
                         ...
                         ]).
                It list the types and their associated values.
				for example :
				domains([object([a,b]), person([john, caty])]).

			    target_concept([]).
			    that gives the clausal theory (set of clauses) representing
				the target concept. 
*/
/* ============================== DIRECTIVES ================================ */

       /* needed operators */

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

:- 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)). 

									% first called goal
:- initialization top_goal.


/* =================== TOP GOAL AND INITIALIZATIONS ========================= */

	/* top goal of the swipl script */
top_goal :-

	writeln('creating intentional examples...'),

	get_arguments(
				  Background_file, 			% file containing background
                      Nb_required_examples,   	% # examples to create
				  File_examples			% file containing examples
                   ),

	modules_initialization,
										% get language and concept
	consult_background_knowledge(bk, Background_file),
	get_clauses_background(bk, LClauses_bkg),
	get_modes(bk, LModes),
	get_irrelevant(bk, LIrrelevant),
	get_domains_concept(bk, LDomains, Head_concept_mode, Target_concept),

	init,

	discard_plus_minus(LModes, LModes1),
     discard_plus_minus([Head_concept_mode], [Head_concept_mode1]),

								% build the models
	build_all_models(LDomains, LClauses_bkg, LModes1, LIrrelevant, LTables),
	build_all_heads_concept(Head_concept_mode1, LDomains, LHeads),
	LTables1 = [LHeads|LTables],
	assign_tables_length(LTables1, LTables_length),
	
											% build the examples
	build_intentional_examples(LTables_length, Target_concept, LDomains,
                                Nb_required_examples, 0, 0, LPos, LNeg),

	write_examples(File_examples, LPos, LNeg),

	writeln('finished.'),
	halt(0).


get_arguments(Background_file, Nb_required_examples,File_examples) :-
        current_prolog_flag(argv, Argv),
        append(_, [Background_file, 
                   Nb_required_examples1, File_examples], Argv),
        atom_number(Nb_required_examples1, Nb_required_examples).


   /* modules called */            
modules_initialization :-
   getenv('LEAR_DIR', Lear),
   atom_concat(Lear, '/intentional_data.pl', Int),
   use_module(Int),
   atom_concat(Lear, '/counter.pl', Count),
   use_module(Count),
   atom_concat(Lear, '/formated_writing.pl', Format),
   use_module(Format),
   atom_concat(Lear, '/utilities_lear11.pl', Utils),
   use_module(Utils),
   atom_concat(Lear, '/completion2.pl', Completion),
   use_module(Completion),
   atom_concat(Lear, '/counter.pl', Counter),
   use_module(Counter),
   atom_concat(Lear, '/randomize.pl', Random),
   use_module(Random),
   atom_concat(Lear, '/randomize.pl', Random),
   use_module(Random),
   atom_concat(Lear, '/list.pl', List),
   use_module(List),
   atom_concat(Lear, '/graph_examples2.pl', Graph),
   use_module(Graph),
   atom_concat(Lear, '/miscellaneous.pl', Misc),
   use_module(Misc),
   atom_concat(Lear, '/compatibility5.pl', Comp),
   use_module(Comp),
   atom_concat(Lear, '/domains.pl', Domains),
   use_module(Domains),
   atom_concat(Lear, '/term.pl', Term),
   use_module(Term).
	

init :-
   reset_count(nb_ex),
   init_randomize,
   set_learn_mode(train),

   get_types(bk, LTypes),
   bk:assert(types(LTypes)),

   bk:types_instantiable(LTypes_instantiable),
   subtract(LTypes, LTypes_instantiable, LTypes_not_instantiable),
   bk:assert(types_not_instantiable(LTypes_not_instantiable)),
 
   build_list_types_under_oi(bk),
   set_types_not_under_oi(bk),
   build_list_types_not_under_oi(bk),
                     
   findall(Atom, (bk:mode(Atom) ; bk:target_mode(Atom)), LAtoms), 
   discard_plus_atoms(LAtoms, LAtoms1),
   build_atoms_types(bk,LAtoms1).


/* ==================== BUILDING intentional EXAMPLES ======================= */

	/* draw  Nb_pos_examples positive examples and 
	         Nb_neg_examples negative examples
		from the modeles of the background knowledge.
		The labels of the examples are assigned according to they
		satisfy or not the Target_concept */

				% all the examples are drawn
build_intentional_examples(
                            _LTables_length, _Target_concept, _LDomains,
                            Nb_required_examples, Nb_pos_drawn, Nb_neg_drawn,
                            [], []
                           ) :-
	Nb_required_examples is Nb_pos_drawn + Nb_neg_drawn,
	!.


				% must draw positive and negative examples
build_intentional_examples(
							LTables_length,     % lengths of the Tables
							Target_concept,		
							LDomains,	
                                   Nb_required_examples,	% # of wanted +  examples
                                   Nb_pos_drawn, 		     % # of drawn  +  examples
							Nb_neg_drawn,
							LPos, 				% final set of + examples
							LNeg				% final set of - examples
						   ) :-

	draw_example(LTables_length, [Head|Body]),
	get_count(nb_ex, Number_ex),
     train:assert(domains(Number_ex, _, LDomains)),

								% prepare example
	body_to_tables(Body, LTables_ex),
	build_graph_from_tables(LTables_ex, Graph_ex),
	count_tables_possibilities(LTables_ex, 1, LTables_possibilities),

								% check label
	assign_label(Target_concept, Head, Graph_ex, LTables_possibilities, Label),	

	place_example_and_draw_again(LTables_length, Target_concept, LDomains,
                                 Head, Body, Label, 
                                 Nb_required_examples, 
                                 Nb_pos_drawn, Nb_neg_drawn,
                                 LPos, LNeg).


				% a positive example has been drawn
place_example_and_draw_again(
                              LTables_length, Target_concept, LDomains,
                              Head, Body, positive, 
                              Nb_required_examples,  
                              Nb_pos_drawn, Nb_neg_drawn,
                              [(Body, LDomains, Head)|LPos], LNeg):-
	!,
	Nb_pos_drawn1 is Nb_pos_drawn + 1,
     read_count(nb_ex, Number_ex),
	display_example(Number_ex, Nb_pos_drawn1, Nb_neg_drawn),
	build_intentional_examples(LTables_length, Target_concept, LDomains,
							   Nb_required_examples, 
							   Nb_pos_drawn1, Nb_neg_drawn,
							   LPos, LNeg).

	
				% a negative example has been drawn
 place_example_and_draw_again(LTables_length, Target_concept, LDomains,
                               Head, Body, negative, 
                               Nb_required_examples,
                               Nb_pos_drawn, Nb_neg_drawn,
                               LPos, [(Body, LDomains, Head)|LNeg]) :-
	Nb_neg_drawn1 is Nb_neg_drawn + 1,
	read_count(nb_ex, Number_ex),
	display_example(Number_ex, Nb_pos_drawn, Nb_neg_drawn1),
	build_intentional_examples(LTables_length, Target_concept, LDomains, 
							   Nb_required_examples, 
							   Nb_pos_drawn, Nb_neg_drawn1,
							   LPos, LNeg).
	

	/* draw an example (a model of the background knowledge)
       by drawing a possibility in each table */

				% no more table to explore
draw_example([], []) :-
	!. 

draw_example([tl(Table,Length)|LTables],LPossibilities) :-
	draw_integer(1, Length, Index),
	nth1(Index, Table, Possibility),
	draw_example(LTables, LPossibilities1),
	append(Possibility, LPossibilities1, LPossibilities).



	/* assign a label + if Example is theta-subsumed by Target_concept */
assign_label(Target_concept, Head, Graph_ex, LTables_possibilities, positive) :-
	covers_example(Target_concept, Head, Graph_ex, 
                   LTables_possibilities),
	!.

assign_label(_Target_concept, _Head, _Graph_ex, 
             _LTable_possibilities, negative).
	

/* ========================= CHECK SUBSUMPTION ============================== */

	/* check whether a set of Clauses covers Example. 
	   This means that at least a Clause theta-subsumes Example */
covers_example([], _Head, _Graph, _LTables_possibilities) :-
        !,
        fail.

covers_example(
               [Clause|_LClauses],
               Head, Graph, 
			   LTables_possibilities
              ) :-
	compatible_pos(Clause, (1, Head, Graph), (1, LTables_possibilities)),
    !.

covers_example([_Clause|LClauses], Head, Graph, LTables_possibilities) :-
        covers_example(LClauses, Head, Graph, LTables_possibilities).


/* ============ BUILD ALL POSSIBLE HEADS OF THE TARGET CONCEPT ============== */

	/* build all possible heads of concept according to the types 
	   appearing in the head */

build_all_heads_concept(Head_concept_mode, LDomains, LHeads) :-
	Head_concept_mode =..[Head_name|LTypes],
	get_types_values(LTypes, LDomains, LTypes_values),
	build_possible_head_arguments(LTypes_values, LArguments),
	build_heads_concept(Head_name, LArguments, LHeads).


	/* get the possible values for each argument-type of the head */
get_types_values([], _LDomains, []) :-
   !.
					% used type found
get_types_values([Type|LTypes], LDomains, [Values|LValues]) :-
	member(Type_and_values, LDomains),
	Type_and_values=..[Type|[Values]],
	!,
	get_types_values(LTypes, LDomains, LValues).
		
					% non used type found
get_types_values([_Type|LTypes], LDomains, LTypes_values) :-
	get_types_values(LTypes, LDomains, LTypes_values).
		

	/* build all possibilities by picking one value in a list of values
	   for each argument of the head */
build_possible_head_arguments([], [[]]) :-
	!.

build_possible_head_arguments(LTypes_values, LArguments) :-
	cross_product_lists(LTypes_values, LArguments).


	/* build the possible head of the target concept with Head_name and 
	   a list of possible argument */
 
build_heads_concept(_Head_name, [], []) :-
   !.

build_heads_concept(Head_name, [Arguments|LArguments], [[Head]|LHeads]) :-
   Head =..[Head_name|Arguments],
	build_heads_concept(Head_name, LArguments, LHeads).


/* ========================= WRITE THE RESULTING FILE ======================= */

write_examples(File, LPos, LNeg) :-

   atom_concat(File, '.int', File_out),
   open(File_out, write, Out),

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

         	/* write a list of intentional ambiguous examples */
   write_intentional_examples_domains_targets(1, LPos, pos, Out),
   write_intentional_examples_domains_targets(1, LNeg, neg, Out),
                      
   close(Out).


/* ============================== MISCEALENOUS =============================== */

display_example(Number, Nb_pos, Nb_neg) :-
	write(Number),
	write(' : '),
	write(Nb_pos),
	write(' : '),
	writeln(Nb_neg).


	/* transform a list of atoms in a product of tables */
body_to_tables([], []) :-
	!.

body_to_tables([Atom|LAtoms], [[[Atom]]|LTables_atoms]) :-
	body_to_tables(LAtoms, LTables_atoms).


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

assign_tables_length([Table|LTables], [tl(Table,Length)|LTables_length]) :-
	length(Table, Length),
	assign_tables_length(LTables, LTables_length).


	/* get additional pieces of informations about 
		the used language and concept */
get_domains_concept(Module, LDomains, Head_concept_mode, Target_concept) :-
	Module:domains(LDomains),
	Module:target_concept(Target_concept1),
	lear_clauses_to_prolog2(Target_concept1, Target_concept2),
     refresh_variables_list(Target_concept2, Target_concept),
	Module:target_mode(Head_concept_mode).
   

        /* transforme clauses from lear syntax to prolog syntax */
lear_clauses_to_prolog2([], []) :-
   !.

lear_clauses_to_prolog2([Clause|LClauses], [Pclause|LPclauses]) :-
   one_lear_clause_to_prolog2(Clause, Pclause),
   lear_clauses_to_prolog2(LClauses, LPclauses).


one_lear_clause_to_prolog2(Atom <- Body, (Atom,Body1)) :-   % Horn clause
   !,
   enumeration_to_list(Body, Body1).

one_lear_clause_to_prolog2(Atom, [Atom]).  				% positive clause : a1 or a2..


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




