/* ========================================================================== */
/*                         DOMAINS AND TYPES HANDLING                         */
/* ========================================================================== */
 
:- module(
          domains,
          [
            clean_the_types/2,
            get_mode_arguments/3,

            discard_plus_atoms/2,
            discard_modes/2,

            split_oi_domains/3,
            split_instantiable_domains/3,
            update_values_domains/3,

            build_list_types_under_oi/0,
			build_list_types_under_oi/1,

            build_list_types_not_under_oi/0,
            build_list_types_not_under_oi/1,

            get_atom_types/2,
            convert_atoms_types/2,
            get_sets_vars/5,

            variabilize_example/4,
            variabilize_table/5,
            variabilize_conjunction/5,
            variabilize_atom/5,

            check_instantiable_mode/2,
            check_oi_mode/2,

            get_types/1,
		    get_types/2,
			
            build_atoms_types/1,
			build_atoms_types/2,

            set_types_not_under_oi/0,
			set_types_not_under_oi/1
          ]
          ).


:- getenv('LEAR_DIR', Lear),
    atom_concat(Lear, '/miscellaneous.pl', Misc),
    use_module(Misc),
    atom_concat(Lear, '/list.pl', List),
    use_module(List),
    atom_concat(Lear,'/term.pl', Term),
    use_module(Term).
 

/* =============================== PREDICATS ================================ */

	/* recupere les modes associes aux arguments de Atom */
get_mode_arguments(Atom, LModes, LTypes) :-
   variabilize_atom(Atom, Atom1),
   bk:mode_arguments(Atom1),
   Atom1=..[Pred|LModes],
   variabilize_atom(Atom, Atom2),
   bk:mode(Atom2),
   Atom2=..[Pred|LTypes].


  /* discard from instantiable oi domains the values used in Hyp */
update_values_domains([], LDomains_oi, LDomains_oi) :-
   !.

update_values_domains([Atom|LAtoms], LDomains_oi, LDomains_oi_out) :-
   get_atom_types(Atom, LTypes),
   Atom=..[_|LArgs],
   update_values_domains_types(LArgs, LTypes, LDomains_oi, LDomains_oi1),
   update_values_domains(LAtoms, LDomains_oi1, LDomains_oi_out).


   /* discard used values of oi domains in Largs */
update_values_domains_types([], [], LDomains_oi_out, LDomains_oi_out) :-
   !.

update_values_domains_types([Arg|LArg], [Type|LType], 
                            LDomains_oi, LDomains_oi_out) :-
   check_oi_mode(oi, Type),
   \+ var(Arg),              % Arg is a constant of a type under oi
   !,
   functor(Term, Type, 1),
   select(Term, LDomains_oi, LDomains_oi1),
   arg(1,Term, LValues),
   delete(LValues, Arg, LValues1),
   Type1=..[Type,LValues1],
   update_values_domains_types(LArg, LType, 
                              [Type1|LDomains_oi1], LDomains_oi_out).

update_values_domains_types([_Arg|LArg], [_Type|LType], 
                            LDomains_oi, LDomains_oi_out) :-
          % Arg is either a variable or a type not under oi
   update_values_domains_types(LArg, LType, LDomains_oi, LDomains_oi_out).

   
  /* split the domains concerning instantiable and not instantiable types */
split_instantiable_domains([], [], []) :-
   !.

split_instantiable_domains(
                           [Domain|LDomains], 
                           [Domain|LDomains_not_inst], 
                           LDomains_inst
                          ) :-
   Domain=..[Type|_],
   check_instantiable_mode(not_instantiable, Type),
   !,
   split_instantiable_domains(LDomains, LDomains_not_inst, LDomains_inst).

split_instantiable_domains(
                           [Domain|LDomains], 
                           LDomains_not_inst, 
                           [Domain|LDomains_inst]
                          ) :-
   split_instantiable_domains(LDomains, LDomains_not_inst, LDomains_inst).


   /* split the domains concerning types under oi and types not under oi */
split_oi_domains([], [], []) :-
   !.

split_oi_domains([Domain|LDomains], [Domain|LDomains_not_oi], LDomains_oi) :-
   Domain=..[Type|_],
   check_oi_mode(not_oi, Type),
   !,
   split_oi_domains(LDomains, LDomains_not_oi, LDomains_oi).

split_oi_domains([Domain|LDomains], LDomains_not_oi, [Domain|LDomains_oi]) :-
   split_oi_domains(LDomains, LDomains_not_oi, LDomains_oi).

/* =============================== OI managment ============================= */

   /* gather variables of a same type in a same set */
get_sets_vars(_Oi_mode, [], [],  LVars, LVars) :-
    !.                                                                   
       
get_sets_vars(Oi_mode, [Atom|LAtoms], [Atom_type|LAtoms_types], 
                      LVars, LVars1) :-
   Atom      =..[_|LVars_atom],
   Atom_type =..[_|LTypes],
   check_var_type(Oi_mode, LVars_atom, LTypes, LVars, LVars2),
   get_sets_vars(Oi_mode, LAtoms, LAtoms_types, LVars2, LVars1).
   

	/* gather variables corresponding to types under or not oi */
check_var_type(_Oi_mode, [], [], LVars, LVars) :-
   !.
   
                % not a var
 check_var_type(Oi_mode, [X|LVars_atoms], [_Type|LTypes], LVars, LVars1) :-
   \+ var(X),
   !,
   check_var_type(Oi_mode, LVars_atoms, LTypes, LVars, LVars1).
   
                 % var having good oi mode
check_var_type(Oi_mode, [Var|LVars_atoms], [Type|LTypes], LVars, LVars1) :- 
   check_oi_mode(Oi_mode, Type),
   !,
   functor(Atom,Type, 1),
   select(Atom, LVars, LVars2),
   Atom=..[Type|[L]],
   add_var(Var, L, L1),
   Atom1=..[Type|[L1]],
   check_var_type(Oi_mode, LVars_atoms, LTypes, [Atom1|LVars2], LVars1).


               % var not having good oi mode
check_var_type(Oi_mode, [_Var|LVars_atoms], [_Type|LTypes], LVars, LVars1) :-
   check_var_type(Oi_mode, LVars_atoms, LTypes, LVars, LVars1).
   
    
add_var(Var, L, L) :-
   exists_similar_element(Var, L, strictly),
   !.
   
add_var(Var, L, [Var|L]).   
   
/* ================================ PATTERNS ================================ */ 
 

    /* return Conj where arguments have been replaced by instantiable types */
get_patterns_not_instantiable_types(_Module, [], [], []) :-
   !.
        
get_patterns_not_instantiable_types(Module,
                                [Atom|LAtoms], 
                                [Atom1|LAtoms1],
                                [Atom2|LAtoms2]
                               ) :-
   Atom  =..[Pred|LArgs],
   length(LArgs, N),
   functor(Atom1, Pred, N),
   functor(Atom2, Pred, N),
   Module:pattern_not_instantiable_not_oi(Atom1),
   Module:pattern_not_instantiable_oi(Atom2),
   get_patterns_not_instantiable_types(Module, LAtoms, LAtoms1, LAtoms2).  



    /* return Conj where arguments have been replaced by instantiable types */
get_patterns_not_instantiable_types([], [], []) :-
   !.
        
get_patterns_not_instantiable_types(
                                [Atom|LAtoms], 
                                [Atom1|LAtoms1],
                                [Atom2|LAtoms2]
                               ) :-
   Atom  =..[Pred|LArgs],
   length(LArgs, N),
   functor(Atom1, Pred, N),
   functor(Atom2, Pred, N),
   bk:pattern_not_instantiable_not_oi(Atom1),
   bk:pattern_not_instantiable_oi(Atom2),
   get_patterns_not_instantiable_types(LAtoms, LAtoms1, LAtoms2).  



     /* return Conj where arguments have been replaced by instantiable types */
get_patterns_instantiable_types(_Module, [], [], []) :-
   !.
        
get_patterns_instantiable_types(
								Module,
                                [Atom|LAtoms], 
                                [Atom1|LAtoms1],
                                [Atom2|LAtoms2]
                               ) :-
   Atom  =..[Pred|LArgs],
   length(LArgs, N),
   functor(Atom1, Pred, N),
   functor(Atom2, Pred, N),
   Module:pattern_instantiable_not_oi(Atom1),
   Module:pattern_instantiable_oi(Atom2),
   get_patterns_instantiable_types(Module, LAtoms, LAtoms1, LAtoms2).        

    


     /* return Conj where arguments have been replaced by instantiable types */
get_patterns_instantiable_types([], [], []) :-
   !.
        
get_patterns_instantiable_types(
                                [Atom|LAtoms], 
                                [Atom1|LAtoms1],
                                [Atom2|LAtoms2]
                               ) :-
   Atom  =..[Pred|LArgs],
   length(LArgs, N),
   functor(Atom1, Pred, N),
   functor(Atom2, Pred, N),
   bk:pattern_instantiable_not_oi(Atom1),
   bk:pattern_instantiable_oi(Atom2),
   get_patterns_instantiable_types(LAtoms, LAtoms1, LAtoms2).        

 

/* split types in types under oi
   and types not under oi */
split_oi_not_oi(
				Module,
                LTypes,
                LTypes_oi,
                LTypes_not_oi
               ) :-
   Module:types_under_oi(Loi),
   Module:types_not_under_oi(Lnot_oi),
   intersection(LTypes, Loi, LTypes_oi),
   intersection(LTypes, Lnot_oi, LTypes_not_oi).
  


/* split types in types under oi
   and types not under oi */
split_oi_not_oi(
                LTypes,
                LTypes_oi,
                LTypes_not_oi
               ) :-
   bk:types_under_oi(Loi),
   bk:types_not_under_oi(Lnot_oi),
   intersection(LTypes, Loi, LTypes_oi),
   intersection(LTypes, Lnot_oi, LTypes_not_oi).
  


/* ================================ TYPES =================================== */

     /* get types declared in modes */
get_types(Module, LTypes) :-
   findall(LArgs, (Module:mode(Mode), Mode =.. [_|LArgs]), LLArgs),
   get_target_mode(Module, LLArgs1),
   append(LLArgs, LLArgs1, LLArgs2),
   flatten(LLArgs2, LTypes1),
   clean_the_types(LTypes1, LTypes).


     /* get types declared in modes */
get_types(LTypes) :-
   findall(LArgs, (bk:mode(Mode), Mode =.. [_|LArgs]), LLArgs),
   get_target_mode(LLArgs1),
   append(LLArgs, LLArgs1, LLArgs2),
   flatten(LLArgs2, LTypes1),
   clean_the_types(LTypes1, LTypes).


	/* get the target mode if it exists 
      (case used for the program 'discard_noise_int') */
get_target_mode(Module, [LArgs1]) :-
   catch(Module:target_mode(Mode1), _, fail),
   !, 
   Mode1 =.. [_|LArgs1].

get_target_mode(_Module, []).


	/* get the target mode if it exists 
      (case used for the program 'discard_noise_int') */
get_target_mode([LArgs1]) :-
   catch(bk:target_mode(Mode1), _, fail),
   !, 
   Mode1 =.. [_|LArgs1].

get_target_mode([]).


get_all_types(Module, LTypes) :-
        get_types(Module, LTypes).

get_all_types(LTypes) :-
        get_types(LTypes).
        

	/* discard + associated with some types */

clean_the_types(LTypes, LTypes_out) :-
   clean_types(LTypes, LTypes1),
   sort(LTypes1, LTypes_out).


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

clean_types([+Type|LTypes], [Type|LTypes1]) :-
   !,
   clean_types(LTypes, LTypes1).

clean_types([Type|LTypes], [Type|LTypes1]) :-
   clean_types(LTypes, LTypes1).



	/* get the types associated with Atom */
get_atom_types(Module, Atom, LTypes) :-
   Atom=..[Functor|_LArgs],
   Module:pattern_types(Functor, LTypes).


	/* get the types associated with Atom */
get_atom_types(Atom, LTypes) :-
   Atom=..[Functor|_LArgs],
   bk:pattern_types(Functor, LTypes).

	
     /* return Conj where arguments have been replaced by types */
convert_atoms_types([], []) :-
   !.
        
convert_atoms_types([Atom|LAtoms], [Atom1|LAtoms1]) :-
   convert_atom_types(Atom, Atom1),
   convert_atoms_types(LAtoms, LAtoms1).


	/* convert the arguments of an atom to their respective types */
convert_atom_types(Module, Atom, Atom_out) :-
   Atom=..[Functor|_LArgs],
   Module:pattern_types(Functor, Types),
   Atom_out=..[Functor|Types].


	/* convert the arguments of an atom to their respective types */
convert_atom_types(Atom, Atom_out) :-
   Atom=..[Functor|_LArgs],
   bk:pattern_types(Functor, Types),
   Atom_out=..[Functor|Types].
      
        
        
get_patterns_types(Module, LPattern) :-
    findall(
            Pattern, 
            (Module:pattern_types(Functor, LInfos), Pattern=..[Functor|LInfos]), 
            LPattern
           ).     

get_patterns_types(LPattern) :-
    findall(
            Pattern, 
            (bk:pattern_types(Functor, LInfos), Pattern=..[Functor|LInfos]), 
            LPattern
           ).     


   /* discard the + (mode) associated with the arguments of the list of atoms */

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

discard_plus_atoms([Atom|LAtom], [Atom1|LAtom1]) :-
   Atom =..[Pred|LArgs],
   discard_modes(LArgs, LArgs1),
   Atom1 =..[Pred|LArgs1],
   discard_plus_atoms(LAtom, LAtom1).


	/* elimine les modes associés aux types des arguments */

discard_modes([], []) :-
   !.
 
discard_modes([Type|LTypes], [Type1|LTypes1]) :-
   discard_one_mode(Type, Type1),
   discard_modes(LTypes, LTypes1).


discard_one_mode(+Type, Type) :-
   !.

discard_one_mode(Type, Type). 


/* ============================  VARIABILIZATION ============================ */

   /* variabilize constants corresponding to objects to non
      instantiable types */ 
variabilize_example(_Mode, [], _LConst_var, []) :-
   !.
   
variabilize_example(
                     Mode,              % instantiable or not_instantiable
                     [Table|LTable], 
                     LConst_var,        % list of coples (const, var)
                     [Table_seed|LTable_seed]
                    ) :-
        variabilize_table(Mode, Table, LConst_var, LConst_var1, Table_seed), 
        variabilize_example(Mode, LTable, LConst_var1, LTable_seed).


	/* variabilize a table according to LConst_var */
variabilize_table(_Mode, [], LConst_var, LConst_var, []) :-
        !.

variabilize_table(
                   Mode,
                   [Possibility|LPossibility], 
                   LConst_var, 
                   LConst_var_out, 
                   [Seed|LSeed]
                 ) :-
        variabilize_conjunction(Mode, Possibility, LConst_var, LConst_var1, Seed),
        variabilize_table(Mode, LPossibility, LConst_var1, LConst_var_out, LSeed).   


   /* variabilize conjunction by replacing constants by variables */
variabilize_conjunction(_Mode, [], LConst_var, LConst_var, []) :-
        !.

variabilize_conjunction(
                        Mode,
                        [Atom|LAtoms],  
                        LConst_var,            % pairs (const, var) built
                                               % so far
                        LConst_var_out,        % final pairs (const, var)
                        [Atom_var|LAtom_var]
                       ) :-  
        variabilize_atom(Mode, Atom, LConst_var, LConst_var1, Atom_var),               
        variabilize_conjunction(Mode, LAtoms, LConst_var1, LConst_var_out, 
                                LAtom_var).
        

	/* variabilize on atom */
variabilize_atom(Mode, neg(Atom), LConst_var, LConst_var_out, neg(Atom_var)) :-
   !,
   variabilize_atom(Mode, Atom, LConst_var, LConst_var_out, Atom_var).

        
variabilize_atom(Mode, Atom, LConst_var, LConst_var_out, Atom_var) :-
    Atom =..[Functor|LConsts],             % constants in atom
    bk:pattern_types(Functor, LTypes),     % type of constants
    variabilize_constants(Mode, LTypes, LConsts, LConst_var, LConst_var_out, 
                          LVars),
    Atom_var =..[Functor|LVars].   
   

        /* variabilize constants according to Mode */
variabilize_constants(_Mode, [], [], LConsts_vars, LConsts_vars, []) :-
        !.
    
                         % not good mode so no variabilization
variabilize_constants(Mode, [Type|LType], [Const|LConsts], LConsts_vars,
                      LConsts_vars1, [Const|LVars]) :-
        \+ check_instantiable_mode(Mode, Type),        % not good mode
        !,
        variabilize_constants(Mode, LType, LConsts, LConsts_vars,
                                LConsts_vars1, LVars).

	                    % good mode so variabilization
variabilize_constants(
                      Mode,
                      [Type|LType], 
                      [Const|LConsts], 
                      LConsts_vars,
                      LConsts_vars1,
                      [Var|LVars]
                     ) :-
        check_oi(Type),
        member((Const, Type, Var), LConsts_vars),   % type under oi already seen
        !,
        variabilize_constants(Mode, LType, LConsts, LConsts_vars, 
                              LConsts_vars1, LVars).

        % either first occurrence under oi, or not oi type
        % Const is simply variabilized
variabilize_constants(Mode, 
                       [Type|LType], 
                       [Const|LConsts], LConsts_vars,
                       LConsts_vars1, [Var|LVars]) :-
        !,              
        variabilize_constants(
                              Mode,
                              LType, LConsts, [(Const, Type, Var)|LConsts_vars], 
                              LConsts_vars1, LVars).


        /* variabilize all constants (not under oi) of the current table */
variabilize_table_values([], []) :-
   !.
   
variabilize_table_values([Possibility|LPossibilities],
                  [Possibility1|LPossibilities1]) :-
   variabilize_atoms_values(Possibility, Possibility1),
   variabilize_table_values(LPossibilities, LPossibilities1).      


   /* each arg under oi is variabilized */       
variabilize_args_under_oi([], _LIndices, []) :- 
   !.
   
variabilize_args_under_oi([Instance|LInstance], LIndices, 
                          [Instance1|LInstances1]) :-
   variablize_args_according_index(LIndices, Instance, Instance1),
   variabilize_args_under_oi(LInstance, LIndices, LInstances1).
 

   /* each args of index Index in Instance is replaced by a variable */ 
variablize_args_according_index([], Instance, Instance) :-
   !.
   
variablize_args_according_index([Index|LIndex], Instance, Instance1) :-
   setarg(Index, Instance, _Var),
   variablize_args_according_index(LIndex, Instance, Instance1).


	/* check whether Type is under or not under oi */

 check_oi(_Type) :-
   catch(learn:force_oi(true), _E, fail),     % option force_oi (for the seed) is true
   !.

 check_oi(Type) :-
   check_oi_mode(oi, Type).

/* ========================================================================== */   
   
   /* discard Instantiations that appear in all possibilities of any
      negative example :
      IMPORTANT : FAUX NE PAS FAIRE car 
      + : p(a) et q(b) 
      - : p(a) et q(c)
      bon hypothese p(a) et q(b) */
 

   /* get all the instantiations of Pattern in positive examples */
get_instantiations_pos([], _, []) :-
   !.
   
get_instantations_pos([Ex|LEx], Pattern, LInstantiations) :-
   get_instantiations_one_pos(Ex, Pattern, LInstantiations1),
   get_instantiations_pos(LEx, Pattern, LInstantiations2),
   append(LInstantiations1, LInstantiations2, LInstantiations).
   
   
    /* get all the instantiations of Pattern in the current pos example */ 
get_instantiations_one_pos([], _Pattern, []) :-
   !.
    
get_instantiations_one_pos([Tab|LTab], Pattern, LInstantiations) :-
   get_instantiations_one_tab(Tab, Pattern, LInstantiations1),
   get_instantiations_one_pos(LTab, Pattern, LInstantiations2),
   append(LInstantiations1, LInstantiations2, LInstantiations).
   
   
   /* get all the instantiations of Pattern in the current table */   
get_instantiations_one_tab([], _Pattern, []) :-
   !.
    
get_instantiations_one_tab([Possibility|LPossibility], 
                           Pattern, LInstantiations) :-
   findall(Pattern, member(Pattern, Possibility), LInstantiations1),
   get_instantiations_one_tab(LPossibility, Pattern, LInstantiations2),
   append(LInstantiations1, LInstantiations2, LInstantiations).   
    
   
        /* select patterns whose at least one argument is a type not under oi */
select_valid_patterns_not_oi([], []) :-
   !.
        
select_valid_patterns_not_oi([Pattern|LPattern], LPattern_out) :-
   Pattern =..[_Pred|LArgs],
   delete(LArgs, oi, []),       % current Pattern is not valid
   !,                           % because all arguments are under oi
   select_valid_patterns_not_oi(LPattern, LPattern_out).
   
select_valid_patterns_not_oi([Pattern|LPattern],[Pattern|LPattern_out]) :-
   select_valid_patterns_not_oi(LPattern, LPattern_out).     % Pattern ok
  

       /* select patterns that has at least one argument of instantiable type */
select_patterns_instantiable([], []) :-
   !.
        
select_patterns_instantiable([Pattern|LPattern], LPattern_out) :-
   check_instantiable_mode(instantiable, Pattern),
   !,
   select_patterns_instantiable(LPattern, LPattern_out).
   
select_patterns_instantiable([_Pattern|LPattern],LPattern_out) :-
   select_patterns_instantiable(LPattern, LPattern_out).     
 
  

   /* check whether we face with an instantiable type or not instantiable */
check_instantiable_mode(instantiable, Type) :-
   !,
   bk:types_instantiable(LTypes),
   member(Type, LTypes).

check_instantiable_mode(not_instantiable, Type) :-
   bk:types_not_instantiable(LTypes),
   member(Type, LTypes).


   /* check whether we face with a type under oi */
check_oi_mode(oi, Type) :-
   !,
   bk:types_under_oi(LTypes),
   member(Type, LTypes).

check_oi_mode(not_oi, Type) :-
   bk:types_not_under_oi(LTypes),
   member(Type, LTypes).
 
 
	/* build patterns of types of each predicate*/   
build_atoms_types(_Module, []) :-
   !.
  
build_atoms_types(Module, [Atom|LAtoms]) :-
   Atom=..[Functor|LTypes],
   Module:assert(pattern_types(Functor, LTypes)),
   build_atoms_types(Module, LAtoms).  


	/* build patterns of types of each predicate*/   
build_atoms_types([]) :-
   !.
  
build_atoms_types([Atom|LAtoms]) :-
   Atom=..[Functor|LTypes],
   bk:assert(pattern_types(Functor, LTypes)),
   build_atoms_types(LAtoms). 
                        
  
set_types_not_under_oi(Module) :-
  catch(Module:types_not_under_oi(_L), _, fail),
   !.                                      
  
set_types_not_under_oi(Module) :-
   get_all_types(Module, LTypes),
   Module:types_under_oi(LTypes_oi),
   subtract(LTypes, LTypes_oi, LTypes_not_oi),
   Module:assert(types_not_under_oi(LTypes_not_oi)).
   

set_types_not_under_oi :-
  catch(bk:types_not_under_oi(_L), _, fail),
   !.                                      
  
set_types_not_under_oi :-
   get_all_types(LTypes),
   bk:types_under_oi(LTypes_oi),
   subtract(LTypes, LTypes_oi, LTypes_not_oi),
   bk:assert(types_not_under_oi(LTypes_not_oi)).
   


build_list_types_not_under_oi(Module) :-
   catch(Module:sets_vars_not_under_oi(_L), _, fail),
   !.      

build_list_types_not_under_oi(Module) :-  
   Module:types_not_under_oi(LTypes),
   make_sets_vars(LTypes, LTypes_not_oi),
   Module:assert(sets_vars_not_under_oi(LTypes_not_oi)).

build_list_types_not_under_oi :-
   catch(bk:sets_vars_not_under_oi(_L), _, fail),
   !.                                      
   
build_list_types_not_under_oi :-  
   bk:types_not_under_oi(LTypes),
   make_sets_vars(LTypes, LTypes_not_oi),
   bk:assert(sets_vars_not_under_oi(LTypes_not_oi)).
   
   
make_sets_vars([], []) :-
   !.                                       % no type not under OI
   
make_sets_vars([Type|LTypes], [Atom|LTypes1]) :-
   Atom =.. [Type|[[]]],
   make_sets_vars(LTypes, LTypes1).   
   
      
  /* build list of types under oi */
build_list_types_under_oi(Module) :-
   catch(Module:sets_vars_under_oi(_L), _, fail),
   !.                                                           
   
build_list_types_under_oi(Module) :-  
   Module:types_under_oi(LTypes),
   make_sets_vars(LTypes, LTypes_oi),
   Module:assert(sets_vars_under_oi(LTypes_oi)).


   /* build list of types under oi */
build_list_types_under_oi :-
   catch(bk:sets_vars_under_oi(_L), _, fail),
   !.                                                           
   
build_list_types_under_oi :-  
   bk:types_under_oi(LTypes),
   make_sets_vars(LTypes, LTypes_oi),
   bk:assert(sets_vars_under_oi(LTypes_oi)).
   
/* ================================ END OF LISTING ========================== */                   
