/* ========================================================================== */
/*             TRANSFORM MULTI-TABLES EXAMPLES IN GRAPHS OF INDICES           */
/*                               (AND CONVERSELY)                             */
/*                 Dominique Bouthinon (LIPN, Universite Paris13)             */
/*                                 (11/02/13)                                 */  
/*  History:                                                                  */
/*            - positive and negative examples are represented by             */
/*              their sets of maximal and  minimal possitilities              */
/*              (8/02/2013)                                                   */                                                                       
/* ========================================================================== */
 
:- module(
           graph_examples2,
           [
			 count_tables_possibilities/3,
			 build_graph_from_tables/2,
             build_tables_from_graph/3,
             create_tables_possibilities/2,
             build_graph_examples/2
           ]
         ).
  
:-
   getenv('LEAR_DIR', Lear),
  
   atom_concat(Lear, '/list.pl', List),
   use_module(List),
   atom_concat(Lear, '/term.pl', Term),
   use_module(Term).

/* =========================== BUILD TABLES FROM GRAPHS ===================== */

	/* build tables and possibilites from graph examples */
build_tables_from_graph(
                         graph(Id, Head, Graph), 
                         tabs(Id, Tabs), 
                         tables(Id, Head, LTables_out)
                       ) :-
   create_empty_possibilities(Tabs, LTables),
   convert_graph_in_tables(Graph, LTables, LTables_out).


     /* create an empty ambiguous examples with empty possibilities */
create_empty_possibilities([], []) :-
   !.

create_empty_possibilities(
                            [(_Num_table, Possibilities)|LTabs],
                            [Table|LTables]
                           ) :-
    length(Possibilities, N),
    create_possibilities(N, Table),
    create_empty_possibilities(LTabs, LTables).
   
	/* create N empty possibilities */
create_possibilities(0, []) :-
   !.

create_possibilities(N, [[]|LPossibilities]) :-
   N1 is N-1,
   create_possibilities(N1, LPossibilities).


	/* convert a graph representing an example as a list of tables */
convert_graph_in_tables([], LTables, LTables) :-
   !.

convert_graph_in_tables([(_, LInstances)|Graph], LTables, LTables1) :-
   put_instances_in_tables(LInstances, LTables, LTables2),
   convert_graph_in_tables(Graph, LTables2, LTables1).


	/* put each instance in the possibilities of one table */
put_instances_in_tables([], LTables, LTables) :-
   !.

put_instances_in_tables(
                        [(Atom, Num_table, LPossibilities)|LInstances], 
                        LTables, 
                        LTables_out
                       ) :-
   select_nth(Num_table, LTables, Table, LTables2),
   put_instances_in_possibilities(Atom, LPossibilities, Table, Table1), 
   insert_nth(Num_table, Table1, LTables2, LTables3),
   put_instances_in_tables(LInstances, LTables3, LTables_out).


	/* put Atom in the referenced possibilites of Table */
put_instances_in_possibilities(_Atom, [], Table, Table) :-
   !.

put_instances_in_possibilities(Atom, [Num|LNum], Table, Table_out) :-
   select_nth(Num, Table, Possibility, Table2),  
   insert_nth(Num, [Atom|Possibility], Table2, Table3),
   put_instances_in_possibilities(Atom, LNum, Table3, Table_out).


/* ========================= BUILD GRAPHS FROM TABLES ======================= */            

	/* build the examples as graphs */
build_graph_examples([], []) :-
   !.

build_graph_examples([min_max(Ex_min, Ex_max)|LEx], 
                     [min_max(Ex_min, Ex_max_graph)|LEx_graph]) :-
   build_graph_from_tables(Ex_max, Ex_max_graph),
   build_graph_examples(LEx, LEx_graph).


	/* Build a graph from a set of tables */
build_graph_from_tables(Tabs, Graph) :-
   get_predicates(Tabs, [], LPredicates),
   get_atoms_predicates(LPredicates, Tabs, Graph).


	/* get the atoms corresponding to the predicates in LPredicates,
      and their locations in the tables Tabs */
get_atoms_predicates([], _Tabs, []) :-
   !.

get_atoms_predicates([(Predicate_name, Arity)|LPredicate], Tabs, 
                     [(Pred1,LAtoms_one_pred)|LAtoms_preds]) :-
   functor(Pred, Predicate_name, Arity),
   make_variables_anonymous(Pred, Pred1),
   get_atoms_one_predicate(Tabs, 1, Pred, LAtoms_one_pred),
   LAtoms_one_pred \== [],
   !,
   get_atoms_predicates(LPredicate, Tabs, LAtoms_preds).

get_atoms_predicates([_|LPredicate], Tabs, LAtoms_preds) :-
    get_atoms_predicates(LPredicate, Tabs, LAtoms_preds).   



	/* get the atoms corresponding to the predicate Predicate 
      and their locations in the tables LTab */
get_atoms_one_predicate([], _Num_tab, _Predicate, []) :-
   !.

get_atoms_one_predicate(
								[Tab|LTab], 
                        Num_tab,			% index of the current table 
                        Predicate,
                        LAtoms_tabs_out
                       ) :-
   get_atoms_one_predicate_tab(Tab, Num_tab, 1, Predicate, [], LAtoms_this_tab),
   Num_tab1 is Num_tab + 1,
   get_atoms_one_predicate(LTab, Num_tab1, Predicate, LAtoms_tabs),
   append(LAtoms_this_tab, LAtoms_tabs, LAtoms_tabs_out).


	/* get the atoms corresponding to the predicate Predicate
      and their locations in the possibilities of table */
get_atoms_one_predicate_tab([], _Num_tab, _Num_possibility, _Predicate,   
                            LAtoms, LAtoms) :-
   !.
                         
get_atoms_one_predicate_tab(
                            [Possibility|LPossibility], 
                            Num_tab,
                            Num_possibility,   % index of the possibility in
                                               % the current table
                            Predicate, 
                            LAtoms_seen,       % atoms of Predicate found 
                                               % in the table
                            LAtoms             % all atoms of Predicate in
                                               % in the table
                            ) :-
   get_atoms_one_predicate_possibility(Possibility, Num_tab, Num_possibility,
                                       Predicate, LAtoms_seen, LAtoms_seen1),
   Num_possibility1 is Num_possibility + 1,
   get_atoms_one_predicate_tab(LPossibility, Num_tab, Num_possibility1, 
                               Predicate, LAtoms_seen1, LAtoms).


/* get the atoms corresponding to the predicate Predicate
   in the current Possibility */

get_atoms_one_predicate_possibility(Possibility, Num_tab, Num_possibility,
                                    Predicate, LAtoms_seen, LAtoms_seen_out) :-
   findall(Predicate, member(Predicate, Possibility), LAtoms1),
   sort(LAtoms1, LAtoms2),
   check_atoms(LAtoms2, Num_tab, Num_possibility, LAtoms_seen, LAtoms_seen_out).


	/* check whether the atoms in LAtoms are in LAtoms, and add associate
      pieces of information */
check_atoms([], _Num_tab, _Num_possibility, LAtoms_seen, LAtoms_seen) :-
   !.

check_atoms([Atom|LAtoms], Num_tab, Num_possibility, 
            LAtoms_seen, LAtoms_seen_out) :-
   select((Atom, Num_tab, LPossibility), LAtoms_seen, LAtoms_seen1),
   add_num_possibility(Num_possibility, LPossibility, LPossibility1),
   check_atoms(LAtoms, Num_tab, Num_possibility, 
               [(Atom,Num_tab, LPossibility1)|LAtoms_seen1], LAtoms_seen_out).
	
   % Atom not referenced yet in LAtoms_seen
check_atoms([Atom|LAtoms], Num_tab, Num_possibility, 
            LAtoms_seen, LAtoms_seen_out) :-
    check_atoms(LAtoms, Num_tab, Num_possibility, 
                [(Atom, Num_tab, [Num_possibility])|LAtoms_seen], 
                LAtoms_seen_out).


	/* add Num_possibility whether it is not in LPossibility */
add_num_possibility(Num_possibility, LPossibility, LPossibility) :-
   member(Num_possibility, LPossibility),
   !.

add_num_possibility(Num_possibility, LPossibility, 
                    [Num_possibility|LPossibility]).
   

	/* get the predicates used in the tables */
get_predicates([], LPredicates, LPredicates) :-
   !.

get_predicates([Tab|LTab], LPredicates1, LPredicates) :-
   get_predicate_table(Tab, LPredicates1, LPredicates2),
   get_predicates(LTab, LPredicates2, LPredicates).


	/* get the predicates used in one table */
get_predicate_table([], LPredicates, LPredicates) :-
   !.

get_predicate_table([Possibility|LPossibility], LPredicates1, LPredicates) :-
   get_predicate_possibility(Possibility, LPredicates1, LPredicates2),
   get_predicate_table(LPossibility, LPredicates2, LPredicates).


	/* get the predicates used on one possibility */
get_predicate_possibility([], LPredicates, LPredicates) :-
   !.

get_predicate_possibility([Atom|LAtom], LPredicates1, LPredicates) :-
   functor(Atom, Name, Arity),
   \+ member((Name, Arity), LPredicates1),  % first occurrence of the predicate
   !,
   get_predicate_possibility(LAtom, [(Name,Arity)|LPredicates1], LPredicates).

	% Predicate of Atom already found
get_predicate_possibility([_Atom|LAtom], LPredicates1, LPredicates) :-
   get_predicate_possibility(LAtom, LPredicates1, LPredicates).


/* ========== BUILDS NUMBERS IDENTIFYING POSSIBILITIES OF EXAMPLES ========== */

	/* numbers the possibilites in each table of each example */
create_tables_possibilities([], []) :-
   !.

create_tables_possibilities(
                             [(N, _Head, min_max(_Ex_min, Ex_max)) |LEx], 
                             [(N, Count_max)|LCount]) :-
	count_tables_possibilities(Ex_max, 1, Count_max),
     create_tables_possibilities(LEx, LCount).


count_tables_possibilities([], _Num_table, []) :-
   !.

count_tables_possibilities(
                           [Table|LTable], 
                           Num_table, 
                           [(Num_table, LNumbers)|LCount]
                          ) :-
   count_possibilities(Table, 1, LNumbers),
   Num_table1 is Num_table + 1,
   count_tables_possibilities(LTable, Num_table1, LCount).


	/* count the possibilities in a table */
count_possibilities([], _Num_possibility, []) :-
   !.

count_possibilities(
                     [_Possibility|LPossibility], 
                     Num_possibility,
                     [Num_possibility|LNum_possibility]
                   ) :-
   Num_possibility1 is Num_possibility + 1,
   count_possibilities(LPossibility, Num_possibility1, LNum_possibility).

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