1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    2% Bousi-Prolog to Prolog (TPL) translator
    3
    4:- module(translator, [
    5		translate_program/4,    % +InputProgram, +InputOntology,
    6		                        %  +OutputFile, +StateFile
    7		translate_query/4       % +String, -Query, -Bindings, -Degree
    8   ]).    9
   10:- use_module(parser).   11:- use_module(evaluator).   12:- use_module(flags).   13:- use_module(utilities).   14
   15:- use_module(library(lists)).   16
   17%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   18
   19:- set_prolog_flag(double_quotes, codes).   20
   21
   22%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   23% Translation of Bousi-Prolog files
   24%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 translate_program(+InputProgram, +InputOntology, +OutputFile, +StateFile)
Reads a Bousi-Prolog program together with a Bousi-Prolog ontology, performs a lexical, syntactic and semantic analysis, and generates an intermediate TPL file that can directly be loaded into Prolog. InputOntology can be '' (an empty string) if no ontology is needed. Current flags are saved in StateFile.

If the compilation of the program or the ontology causes an error, this predicate will fail and won't generate anything.

   39translate_program(InputProgram, InputOntology, OutputFile, StateFile) :-
   40	% Parses the specified program and ontology files and gets all the
   41	% directives, rules and equations that are defined in them
   42	parser:parse_program(InputProgram, InputOntology, Directives, Rules,
   43	                     Equations, LingTerms, Messages),
   44	!,
   45	% Builds a list with the text of the messages returned by parser
   46	Template = [_File, _Line, _Column, Text, _Type],
   47	findall(Text, member(Template, Messages), TextMessages),
   48	% Checks if parser generated any error
   49	(member([_, _, _, _, error], Messages) ->
   50		% Shows errors and warnings and then stops translation
   51		forall(member(Message, TextMessages), (write(Message), nl)),
   52		fail
   53	;
   54		% Warnings aren't shown here because they'll be shown when
   55		% loading the TPL file
   56		true
   57	),
   58	% List of t-norms for the different relations
   59	build_t_norms(Directives,TNorms),
   60	% Adds the linguistic terms to the list of fuzzy subsets found in
   61	% source code
   62	add_linguistic_terms(LingTerms, AddedSubsets),
   63	% Computes the closure of each fuzzy relation 
   64	expand_equations([sim, gEqThan, lEqThan, frel1, frel2, frel3],
   65	                 Equations, ExpEquations1),
   66  % Converts the fuzzy sets into a list of equations of the binary fuzzy relation	sim
   67  translate_fuzzy_sets([], ExpEquations2),
   68	append(ExpEquations1, ExpEquations2, ExpEquations),
   69	build_block_equations(ExpEquations, ExpBlockEquations),
   70	% Expands the list of rules using the proximity/similarity relation
   71	utilities:simplify_filename(InputProgram, ProgramPrefix),
   72	expand_rules(Rules, ExpRules, ProgramPrefix, ExpEquations),
   73	% Writes TPL code to output file
   74	telling(CurrentOutput),
   75	tell(OutputFile),
   76	writeq((:- style_check([-singleton, -discontiguous]))), write('.'), nl,
   77	(Messages == [] ->
   78		true
   79	;
   80		% Writes warnings in TPL file to show them each time the file is loaded
   81		create_writes(TextMessages, Writes),
   82		writeq((:- initialization(Writes))), write('.'), nl
   83	),
   84	utilities:write_lines(Directives, '', '.'), nl,
   85	utilities:write_lines(TNorms, '', '.'), nl,
   86	(AddedSubsets == [] ->
   87		true
   88	;
   89		% Adds new fuzzy_set/2 directives to define the linguistic terms
   90		% built with the '#' operator found in the BPL code
   91		write_fuzzy_set_directives(AddedSubsets)
   92	),
   93%	(\+ flags:get_bpl_flag(weak_unification('a3')) ->
   94  	utilities:write_lines(ExpEquations, '', '.'), nl,
   95%  ;
   96	  utilities:write_lines(ExpBlockEquations, '', '.'),
   97%	),
   98	nl,
   99	utilities:write_lines(ExpRules, '', '.'), nl,
  100	told,
  101	tell(CurrentOutput),
  102	tell(StateFile),
  103	current_bpl_flags(Flags),
  104%	writef('%w.\n%w.\n', [':- dynamic tpl_flags/1', flags:tpl_flags(Flags)]),
  105%	writef('%w.\n', [tpl_flags(Flags)]),
  106	writef('%w.\n%w.\n', [':- multifile tpl_flags/1', tpl_flags(Flags)]),
  107	told.
 build_t_norms(+Directives, -TNorms)
Returns the list of terms t_norm(Relation,TNorm) representing the t-norm for each Relation. If no directive is available for a given relation, its default t-norm is used instead. These terms are added to the tpl program, so that they define the predicate t_norm/2.
  120build_t_norms(Directives,TNorms) :-
  121  findall(t_norm(Relation,Type),
  122            (member(fuzzy_rel(Relation,Properties),Directives),
  123             member(transitive(Type),Properties)
  124            ),
  125          FTNorms
  126          ),
  127  (member(t_norm('~',_Type),FTNorms) -> % '~' must be present in any BPL-program
  128     TNorms=FTNorms
  129   ;
  130     flags:default_t_norm('~',Type),
  131     TNorms=[t_norm('~',Type)|FTNorms]
  132  ).
 create_writes(+Messages, -Writes)
Builds a conjunction of write/1 and nl/0 predicates that can be later used to show the specified list of Messages.
  141create_writes([], true).
  142
  143create_writes([Message|MoreMessages], Writes) :-
  144	SingleWrite = (write(Message), nl),
  145	create_writes(MoreMessages, MoreWrites),
  146	(MoreWrites == true ->
  147		Writes = SingleWrite
  148	;
  149		Writes = (SingleWrite, MoreWrites)
  150	).
 write_fuzzy_set_directives(+Subsets)
Writes a directive ':- directive(fuzzy_set, Item).' in current output stream for each Item in Subsets list.
  159write_fuzzy_set_directives([]).
  160
  161write_fuzzy_set_directives([Subset|MoreSubsets]) :-
  162	writeq((:- directive(fuzzy_set, Subset))), write('.'), nl,
  163	write_fuzzy_set_directives(MoreSubsets).
  164
  165
  166
  167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  168% Translation of Bousi-Prolog queries
  169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 translate_query(+String, -Query, -Bindings, -Degree)
Reads the query contained in String, performs a lexical, syntactic and semantic analysis, and returns the following:

If the translation of the query causes an error, this predicate will fail.

  187translate_query(String, Query, Bindings, Degree) :-
  188	% Parses the specified query to get an executable term
  189	flags:get_bpl_flag(program_prefix(ProgramPrefix)),
  190	parser:parse_query(ProgramPrefix, String, ParsedQuery, LingTerms, Messages),
  191	% Builds a list with the text of the error messages returned by parser
  192	Template = [_File, _Line, _Column, Text, error],
  193	findall(Text, member(Template, Messages), TextMessages),
  194	% Checks if parser generated any error
  195	(TextMessages \== [] ->
  196		% Shows errors and then stops translation
  197		forall(member(Message, TextMessages), (write(Message), nl)),
  198		fail
  199	;
  200		true
  201	),
  202	% Converts the executable term into a string and then reads it
  203	% to get the list of variable bindings
  204	swritef(QueryString, '%w.', [ParsedQuery]),
  205	catch((
  206		atom_to_term(QueryString, QueryTerm, AllBindings)
  207	% (catcher)
  208	), _Exception, (
  209		fail
  210	)),
  211	% Removes bindings of unimportant variables (those starting with '_')
  212	findall((VarName = Var),
  213	        (member((VarName = Var), AllBindings), atom_chars(VarName, ['_'|_Chars])),
  214	        UnimportantBindings),
  215	subtract(AllBindings, UnimportantBindings, Bindings),
  216	% Adds the linguistic terms found in the query to the current
  217	% list of fuzzy subsets
  218	add_linguistic_terms(LingTerms, AddedSubsets),
  219	(AddedSubsets == [] ->
  220		% All of the subsets were already on the list, no further
  221		% translation is needed
  222		true
  223	;
  224		% New subsets were found, so new proximity/similarity equations
  225		% must be computed and asserted into the SWI-Prolog database
  226		translate_fuzzy_sets(AddedSubsets, Equations),
  227%		evaluator:add_sim_equations(Equations)
  228		evaluator:update_sim_equations(Equations, Updated),
  229		bplShell:reload_on_extra_equations(Equations, Updated)
  230	),
  231	% Adds the computation of the approximation degree to the query
  232	QueryTerm = [RealQuery, DegreeVars],
  233%	QueryAux = (RealQuery, min_degree(DegreeVars, Degree)),
  234	QueryAux = (RealQuery, degree_composition(DegreeVars, Degree)),
  235	% Translates assert/1 and retract/1 predicates
  236	evaluator:get_sim_equations(CurrentEquations),
  237	translate_asserts_retracts(QueryAux, Query, ProgramPrefix, CurrentEquations).
  238
  239
  240
  241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  242% Expansion of rules
  243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 expand_rules(+Rules, -ExpandedRules, +ProgramPrefix, +Equations)
Scans a list of Rules returned by Bousi-Prolog parser and, for each symbol that is similar to each clause's head (attending to Equations list), builds a translated clause and stores it in the ExpandedRules list. Rules that aren't clauses are copied as is in the output list.

For example, given ProgramPrefix = 'prog', the same rule as in the example of the 'parser' module, [(prog_a(X, DG) :- prog_b(X, D1), prog_c(D2), true), [D1, D2]], and the equations [sim(a, p, 0.5), sim(X, X, 1)], this predicate will return the following set of rules:

 expand_rule(+SimDegrees, +Clause, +RuleDegreeVars, +ProgramPrefix, -ExpandedClauses)
Internal predicate used to expand a single Clause. SimDegrees must be a list consisting of lists with two items: a symbol and an approximation degree.
See also
- expand_rules/4
  278expand_rules([], [], _ProgramPrefix, _Equations).
  279
  280expand_rules([[Rule, HeadConstraintBlockVars, BodyConstraintBlockVars, DegreeVars]|MoreRules], ExpandedRules, ProgramPrefix, Equations) :-
  281	(Rule = (Head :- Body) ->
  282		% Removes the program prefix from the rule's head
  283		functor(Head, FunctorWithPrefix, _Arity),
  284		atom_chars(ProgramPrefix, PrefixChars),
  285		atom_chars(FunctorWithPrefix, FunctorWithPrefixChars),
  286		append(PrefixChars, ['_'], PrefixChars2),
  287		append(PrefixChars2, FunctorChars, FunctorWithPrefixChars),
  288		atom_chars(Functor, FunctorChars),
  289		% Translates the assert/1 and retract/1 predicates of the rule's body
  290		(Body \== true ->
  291			translate_asserts_retracts(Body, NewBody, ProgramPrefix, Equations)
  292		;
  293			NewBody = true
  294		),
  295		% Extracts all the symbols that are similar to this rule's head
  296		findall([Sim, Degree], member(sim(Functor, Sim, Degree), Equations), List),
  297		% Expands this rule using the resulting list
  298		expand_rule(List, (Head :- NewBody), HeadConstraintBlockVars, BodyConstraintBlockVars, DegreeVars, ProgramPrefix, ExpandedRules1)
  299	;
  300		% Rules that aren't clauses don't need expansion
  301		% (note that facts must have 'true' as their body)
  302		ExpandedRules1 = [Rule]
  303	),
  304	% Expands the remaining rules
  305	expand_rules(MoreRules, ExpandedRules2, ProgramPrefix, Equations),
  306	append(ExpandedRules1, ExpandedRules2, ExpandedRules).
  307	
  308
  309expand_rule([], _Clause, _HeadConstraintBlockVars, _BodyConstraintBlockVars, _RuleDegreeVars, _ProgramPrefix, []).
  310
  311expand_rule([[Symbol, Degree]|MoreSimDegrees], Clause, HeadConstraintBlockVars, BodyConstraintBlockVars, RuleDegreeVars, ProgramPrefix, [ExpClause|MoreExpClauses]) :-
  312	Clause = (Head :- Body),
  313	% Creates the lists of variables and approximation degrees that
  314	% will be used in the weak unifications of each rule's argument
  315	Head =.. [_HeadFunctor|HeadArgsWithCtrsAndDegree],
  316	length(HeadArgsWithCtrsAndDegree, ExtendedRuleArity),
  317  actual_rule_arity(ExtendedRuleArity,RuleArity),
  318	length(HeadArgs, RuleArity),
  319	length(HeadVars, RuleArity),
  320	length(HeadDegrees, RuleArity),
  321  append(HeadArgs, CtrsAndDegreeVar, HeadArgsWithCtrsAndDegree),
  322  append(_HeadCtrs,[HeadDegreeVar],CtrsAndDegreeVar),
  323%  init_ctr_store(HeadFunctor,Cin),
  324	create_unification_problems(HeadVars, HeadArgs, HeadCin, HeadCout, HeadDegrees, UnificationProblems),
  325	% Links head and body block constraints variables through the 
  326	% unification problems
  327	link_rule_block_constraint_variables(HeadConstraintBlockVars, BodyConstraintBlockVars, HeadCin, HeadCout),
  328	% Builds the new rule's head with the symbol that is similar to the
  329	% original functor and the variables of the HeadVars list
  330	append(HeadVars, CtrsAndDegreeVar, NewHeadArgsWithCtrsAndDegree),
  331	concat_atom([ProgramPrefix, '_', Symbol], SymbolWithPrefix),
  332	NewHead =.. [SymbolWithPrefix|NewHeadArgsWithCtrsAndDegree],
  333	build_unify_arguments_goal(UnificationProblems,UnifyArgsGoal),
  334	(Degree < 1 ->
  335		% Builds the new rule's body with a check of the lambda-cut value 
  336		% (if needed),
  337		% the weak unification of the arguments, the original body and the
  338		% computation of the approximation degree
  339		append(RuleDegreeVars, HeadDegrees, DegreeVarsAux),
  340		append(DegreeVarsAux, [Degree], DegreeVars),
  341		build_pre_over_lambda_cut_goal(Degree, PreOverLCGoal),
  342    build_degree_composition_goal(DegreeVars, HeadDegreeVar, TNormGoal),
  343		build_post_over_lambda_cut_goal(HeadDegreeVar, PostOverLCGoal),
  344		utilities:append_goals_list([
  345		                   PreOverLCGoal,
  346		                   UnifyArgsGoal,
  347		                   Body,
  348		                   TNormGoal,
  349		                   PostOverLCGoal], 
  350		                  NewBody)
  351	;
  352		% Builds the new rule's body with the weak unification of the
  353		% arguments, the original body and the computation of the
  354		% approximation degree
  355		append(RuleDegreeVars, HeadDegrees, DegreeVars),
  356    build_degree_composition_goal(DegreeVars, HeadDegreeVar, TNormGoal),
  357		build_post_over_lambda_cut_goal(HeadDegreeVar, PostOverLCGoal),
  358		utilities:append_goals_list([
  359		                   UnifyArgsGoal,
  360		                   Body,
  361		                   TNormGoal,
  362		                   PostOverLCGoal], 
  363		                  NewBody)
  364	),
  365	(NewBody==true ->
  366	  ExpClause = (NewHead)
  367	 ;
  368	  ExpClause = (NewHead :- NewBody)
  369	),
  370	% Scans the remaining symbols
  371	expand_rule(MoreSimDegrees, Clause, HeadConstraintBlockVars, BodyConstraintBlockVars, RuleDegreeVars, ProgramPrefix,
  372	            MoreExpClauses).
 build_unify_arguments_goal(+UnificationProblems, -Goal)
Creates a goal for computing the unification of the predicate arguments, expressed as a list of unification problems.
  381build_unify_arguments_goal([], true) :-
  382  !.
  383  
  384build_unify_arguments_goal(UnificationProblems, UnifyArgsGoal) :-
  385	flags:get_bpl_flag(weak_unification(Algorithm)),
  386  atom_concat('unify_arguments_', Algorithm, GoalName),
  387  UnifyArgsGoal =.. [GoalName, UnificationProblems].
  388%  unify_arguments_a1(UnificationProblems)
 build_pre_over_lambda_cut_goal(+Degree, -Goal)
Creates a goal for the rule's lambda-cut threshold. If filtering is enabled and t-norm min is selected, there is no need for this goal, as proximity equations are filtered and rules below such threshold are not generated
  400build_pre_over_lambda_cut_goal(_Degree, true) :-
  401	flags:get_bpl_flag(filtering(true)),
  402%	flags:get_bpl_flag(fuzzy_logic(min)),
  403	!.
  404    
  405build_pre_over_lambda_cut_goal(Degree, over_lambdacut(Degree)).
 build_degree_composition_goal(+DegreeVars, +HeadDegreeVar, -Goal)
Creates a goal for computing the composition of goal degrees, and the head degree of the clause.

build_degree_composition_goal([], 1, true) :- !.

  416% build_degree_composition_goal([D], D, true) :-
  417%   !. 
  418  
  419build_degree_composition_goal(DegreeVars, HeadDegreeVar, degree_composition(DegreeVars, HeadDegreeVar)).
 build_post_over_lambda_cut_goal(+Degree, -Goal)
Creates a goal for a lambda-cut threshold needed for each t-norm whose composition may deal a degree less than the degrees in the composition.
  429build_post_over_lambda_cut_goal(_Degree, true) :-
  430	flags:get_bpl_flag(fuzzy_logic(min)),
  431	!.
  432    
  433build_post_over_lambda_cut_goal(Degree, over_lambdacut(Degree)).
 link_rule_block_constraint_variables(?HeadConstraintBlockVars, ?BodyConstraintBlockVars, ?HeadCin, ?HeadCout)
Links head and body block constraints variables through the unification problems. That is:
  446link_rule_block_constraint_variables(HeadConstraintBlockVars, BodyConstraintBlockVars, HeadCin, HeadCout) :-
  447	HeadConstraintBlockVars = [HeadCin|_],     % Cin of head with Cin of unification problems
  448	BodyConstraintBlockVars = [HeadCout|_],    % Cout of unification problems with Cin of body
  449	!,
  450	append(_,[HCout],BodyConstraintBlockVars), % Cout of body with 
  451	append(_,[HCout],HeadConstraintBlockVars). % Cout of head
  452	
  453% Nothing to do if the body has no constraint block variables (e.g., calls to built-ins)
  454link_rule_block_constraint_variables(_HeadConstraintBlockVars, _BodyConstraintBlockVars, _HeadCin, _HeadCout).
 create_unification_problems(+Vars, +Args, +Degrees, -Problems, ?Cin, ?Cout)
Returns a list of unification Problems suitable for the unify_arguments_ai/1 predicate. If the selected weak unification algorithm is 'a1', then each of the returned problems will be a list with an item of each of the three input lists and the input and output block constraints variables: Vars, Args, and Degrees. Else, the returned problems will be of the form: Vars, Args, Cin, Cout, and Degrees, where the Cout of a unification problem is the Cin of the next one.

For example, given Vars = [X, Y], Args = [a, b] and Degrees = [D1, D2], for 'a1' this predicate will return: Problems = [[X, a, D1], [Y, b, D2]], while for 'a2' and 'a3': Problems = [[X, a, Cin, C1, D1], [Y, b, C1, Cout, D2]]. where Cin and Cout are unbound variables.

  477create_unification_problems(Vars, Args, _Cin, _Cout, Degrees, Goals) :-
  478	flags:get_bpl_flag(weak_unification('a1')),
  479  !,
  480  create_unification_a1_problems(Vars, Args, Degrees, Goals).
  481create_unification_problems(Vars, Args, Cin, Cout, Degrees, Goals) :-
  482  create_unification_a2_a3_problems(Vars, Args, Cin, Cout, Degrees, Goals).
  483
  484create_unification_a1_problems([], [], [], []).
  485create_unification_a1_problems([Var|MoreVars], [Arg|MoreArgs], [Degree|MoreDegrees],
  486                                [[Var, Arg, Degree]|MoreGoals]) :-
  487  create_unification_a1_problems(MoreVars, MoreArgs, MoreDegrees, MoreGoals).
  488
  489create_unification_a2_a3_problems([], [], Cin, Cin, [], []).
  490create_unification_a2_a3_problems([Var|MoreVars], [Arg|MoreArgs], Cin, Cout, [Degree|MoreDegrees],
  491                               [[Var, Arg, Cin, Cin1, Degree]|MoreGoals]) :-
  492  create_unification_a2_a3_problems(MoreVars, MoreArgs, Cin1, Cout, MoreDegrees, MoreGoals).
  493
  494
  495
  496% %% link_block_constraints_variables(?LeftConstraintBlockVars, ?RightConstraintBlockVars)
  497% %
  498% %     Links two lists of block constraints: the last variable of the left
  499% %     list with the first variable of the right list.
  500% %
  501
  502% link_block_constraints_variables(LeftConstraintBlockVars, RightConstraintBlockVars) :-
  503% 	flags:get_bpl_flag(weak_unification('a3')),
  504% 	!,
  505% 	append(_,[Cout],LeftConstraintBlockVars),
  506% 	RightConstraintBlockVars=[Cout|_].
  507
  508% link_block_constraints_variables(_LeftConstraintBlockVars, _RightConstraintBlockVars).
 actual_rule_arity(+ExpandedRuleArity, -RuleArity)
The arity of the expanded rule (with the degree variable and, possibly, with the block constraints variables) corresponds to a predicate without those extended arguments. For the weak unification algorithm 'a1', expanded rules are added only with the resulting degree variable, whereas for 'a2' and 'a3', expanded rules contain also both the input and output block constraint variables. Thus, this predicate computes for a1 RuleArity as ExpandedRuleArity-1 and, for 'a3', ExpandedRuleArity-3.
  523actual_rule_arity(RuleArity, ActualRuleArity) :-
  524	flags:get_bpl_flag(weak_unification('a1')),
  525  !,
  526  ActualRuleArity is RuleArity - 1. % The last argument is the approximation degree
  527  
  528actual_rule_arity(RuleArity, ActualRuleArity) :-
  529  ActualRuleArity is RuleArity - 3. % The last three arguments are: the input and output block constraint stores, and the approximation degree
 expanded_rule_arity(+RuleArity, -ExpandedRuleArity)
The converse predicate to actual_rule_arity/2. In this case, it returns the arity of the translated (expanded) predicate.
  537expanded_rule_arity(RuleArity, ExpandedRuleArity) :-
  538	flags:get_bpl_flag(weak_unification('a1')),
  539  !,
  540  ExpandedRuleArity is RuleArity + 1. % The last argument is the approximation degree
  541  
  542expanded_rule_arity(RuleArity, ExpandedRuleArity) :-
  543  ExpandedRuleArity is RuleArity + 3. % The last three arguments are: the input and output block constraint stores, and the approximation degree
  544
  545  
  546  
  547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  548% Expansion of equations
  549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 expand_equations(+EqPrefix, +Equations, -ExpandedEquations)
Extracts all the equations from the Equations list that match template "EqPrefix(_, _, _)", computes their closure (using the closure properties and t-norm specified in system flags) and returns the resulting equations in the ExpandedEquations list. If EqPrefix is a list, this predicate will be called once for each item and the union of all resulting equations will be returned.
  562expand_equations([], _Equations, []) :-
  563	!.
  564
  565expand_equations([EqPrefix|MorePrefixes], Equations, ExpandedEquations) :-
  566	% Calls this predicate recursively for each prefix
  567	expand_equations(EqPrefix, Equations, ExpandedEquations1),
  568	expand_equations(MorePrefixes, Equations, ExpandedEquations2),
  569	append(ExpandedEquations1, ExpandedEquations2, ExpandedEquations).
  570
  571expand_equations(EqPrefix, Equations, ExpandedEquations) :-
  572	% Extract "EqPrefix(_, _, _)" equations from list
  573	atom(EqPrefix),
  574	utilities:extract_terms(EqPrefix, 3, Equations, SubEquations),
  575	% Computes the reflexive, transitive, and/or symmetric closure
  576	flags:get_bpl_flag(relation_properties(EqPrefix, ClosureProperties)),
  577	utilities:closure_properties(ClosureProperties, Closure, TNorm),
  578	flags:get_bpl_flag(lambda_cut(LambdaCut)),
  579	foreign:ext_closure(SubEquations, Closure, TNorm, EqPrefix, LambdaCut,
  580	                    ExpandedEquations).
  581
  582
  583
  584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  585% Translation of assertions and retractions
  586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 translate_asserts_retracts(+Clause, -TranslatedClause, +ProgramPrefix, +Equations)
Makes a copy of Clause and returns it in TranslatedClause, after expanding all its assert/1 and retract/1 terms. These terms are expanded using ProgramPrefix and the list of Equations in the same way facts and rules are expanded.
For example, considering that "a ~ b = 0.5", a term like "assert(prog_a(g, D))" would be translated into: "(assert((prog_a(A1, D) :- unify_arguments_a1[[A1, g, D1]]), true, min_degree([D1], D)), assert((prog_b(A1, D) :- over_lambdacut(0.5), unify_arguments_a1[[A1, g, D1]]), true, min_degree([D1], D)))"
  606translate_asserts_retracts(Clause, TranslatedClause, ProgramPrefix, Equations) :-
  607	% Program prefix and list of equations are saved in dynamic
  608	% predicates because they're needed by the scanners called
  609	% by process_term/6
  610	assert(program_prefix(ProgramPrefix)),
  611	assert(equations(Equations)),
  612	utilities:process_term(Clause, TranslatedClause,
  613	                       [translator:assert_translator_scanner,
  614	                        translator:retract_translator_scanner],
  615	                       [], _, _),
  616	retract(program_prefix(ProgramPrefix)),
  617	retract(equations(Equations)).
 assert_translator_scanner(+Term, -Result, +InData, -OutData)
Scanner that can be used with process_term/6 to "expand" the assert/1 terms in the same way facts and rules are expanded. See translate_asserts_retracts/2 for an example. This scanner ignores InData and OutData.
See also
- process_term/6
- translate_asserts_retracts/2
  631assert_translator_scanner(Term, Asserts, _, _) :-
  632	nonvar(Term),
  633	Term = assert(Fact),
  634	program_prefix(ProgramPrefix),
  635	equations(Equations),
  636	% Expands the asserted fact and creates a conjunction of
  637	% assert/1 predicates with each of the returned rules
  638	expand_rules([[Fact :- true, [_,_], [], []]], RulesToAssert, ProgramPrefix, Equations),
  639	create_conjunction(RulesToAssert, assert, Asserts).
  640
  641assert_translator_scanner(Term, Term, _, _).
  642	% If term isn't assert/1, it's copied as is
 retract_translator_scanner(+Term, -Result, +InData, -OutData)
Scanner that can be used with process_term/6 to "expand" the retract/1 terms in the same way facts and rules are expanded. See translate_asserts_retracts/2 for an example. This scanner ignores InData and OutData.
See also
- process_term/6
- translate_asserts_retracts/2
  656retract_translator_scanner(Term, Retracts, _, _) :-
  657	nonvar(Term),
  658	Term = retract(Fact),
  659	program_prefix(ProgramPrefix),
  660	equations(Equations),
  661	% Expands the retracted fact and creates a conjunction of
  662	% retract/1 predicates with each of the returned rules
  663	expand_rules([[Fact :- true, [_,_], [], []]], RulesToRetract, ProgramPrefix, Equations),
  664	create_conjunction(RulesToRetract, retract, Retracts).
  665
  666retract_translator_scanner(Term, Term, _, _).
  667	% If term isn't retract/1, it's copied as is
 create_conjunction(+Terms, +Atom, -Conjunction)
Builds a Conjunction of unary predicates using Atom as functor and each of the terms in Terms as arguments.

For example, given Terms = [a, b, c] and Atom = 'write', this predicate will return Conjunction = [write(a), write(b), write(c)].

  680create_conjunction([], _Atom, true).
  681
  682create_conjunction([Item|MoreItems], Atom, Terms) :-
  683	SingleTerm =.. [Atom, Item],
  684	create_conjunction(MoreItems, Atom, MoreTerms),
  685	(MoreTerms == true ->
  686		Terms = SingleTerm
  687	;
  688		Terms = (SingleTerm, MoreTerms)
  689	).
  690
  691
  692
  693%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  694% Predicates for handling linguistic terms
  695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 translate_fuzzy_sets(+Sets, -Equations)
Converts a list of fuzzy sets into a binary fuzzy relation defined with proximity/similarity equations, i.e., 'sim/3' terms. Each fuzzy set must be a list consisting of two terms: a domain name and a list of subsets. If Sets is an empty list, all the current fuzzy sets stored in the BPL flags will be translated.
 translate_fuzzy_sets_aux(+Sets, -Equations)
Internal predicate used by translate_fuzzy_sets/2.
See also
- translate_fuzzy_sets/2
  714translate_fuzzy_sets([], Equations) :-
  715	!,
  716	findall([DomainName, Subsets],
  717	        flags:get_bpl_flag(fuzzy_subsets(DomainName, Subsets)), AllFuzzySets),
  718	translate_fuzzy_sets_aux(AllFuzzySets, Equations).
  719
  720translate_fuzzy_sets(FuzzySets, Equations) :-
  721	translate_fuzzy_sets_aux(FuzzySets, Equations).
  722
  723translate_fuzzy_sets_aux([], []).
  724
  725translate_fuzzy_sets_aux([[Domain, SubsetList]|MoreFuzzySets], Equations) :-
  726	% Gets the domain definition and its current subsets
  727	flags:get_bpl_flag(fuzzy_domain(Domain, [Min, Max, Unit])),
  728	flags:get_bpl_flag(fuzzy_subsets(Domain, FullSubsetList)),
  729	% Translates the subsets into a binary fuzzy relation
  730	foreign:ext_translate_fuzzysets([Domain, Min, Max, Unit], FullSubsetList,
  731	                                SubsetList, sim, DomainEquations),
  732	% Scans the remaining fuzzy subsets
  733	translate_fuzzy_sets_aux(MoreFuzzySets, MoreEquations),
  734	append(DomainEquations, MoreEquations, Equations).
 add_linguistic_terms(+LinguisticTerms, -AddedSubsets)
Translates a list of linguistic terms returned by the parser into a list of fuzzy subsets, and then adds them to the current list of subsets stored in the system flags. AddedSubsets will be unified with the list of new fuzzy subsets that were really added to the flags.

Linguistic terms built with the '#' operator can be defined in two ways:

  754add_linguistic_terms(LingTerms, AddedSubsets) :-
  755	linguistic_terms_to_fuzzy_subsets(LingTerms, Subsets),
  756	add_fuzzy_subsets(Subsets, AddedSubsets).
 linguistic_terms_to_fuzzy_subsets(+LingTerms, -Subsets)
Translates a list of linguistic terms returned by the parser into a list of fuzzy subsets that can be processed by ext_translate_fuzzysets/5. See add_linguistic_terms/2 for the expected syntax of the LingTerms list.
See also
- add_linguistic_terms/2
  769linguistic_terms_to_fuzzy_subsets([], []).
  770
  771linguistic_terms_to_fuzzy_subsets([[domain, DomainName, SubsetDefinition]|MoreLingTerms], Subsets) :-
  772	% Ensures that the specified domain exists
  773	flags:get_bpl_flag(fuzzy_domain(DomainName, [_Min, _Max, _Unit])), !,
  774	% Converts the remaining linguistic terms
  775	linguistic_terms_to_fuzzy_subsets(MoreLingTerms, MoreSubsets),
  776	append([[DomainName, [SubsetDefinition]]], MoreSubsets, Subsets).
  777
  778linguistic_terms_to_fuzzy_subsets([[subset, SubsetName, SubsetDefinition]|MoreLingTerms], Subsets) :-
  779	% Looks for the domain in which a subset called SubsetName is declared
  780	flags:get_bpl_flag(fuzzy_subsets(DomainName, DomainSubsets)),
  781	member(WantedSubset, DomainSubsets),
  782	WantedSubset =.. [SubsetName|_Value],
  783	% Calls the previous rule replacing subset/SubsetName with domain/DomainName
  784	linguistic_terms_to_fuzzy_subsets([[domain, DomainName, SubsetDefinition]], NewSubset),
  785	% Converts the remaining linguistic terms
  786	linguistic_terms_to_fuzzy_subsets(MoreLingTerms, MoreSubsets),
  787	append(NewSubset, MoreSubsets, Subsets).
  788
  789linguistic_terms_to_fuzzy_subsets([_BadLingTerm|MoreLingTerms], Subsets) :-
  790	% This rule is only executed if a linguistic term has an unknown
  791	% syntax or doesn't belong to any existing domain or fuzzy set
  792	linguistic_terms_to_fuzzy_subsets(MoreLingTerms, Subsets).
 add_fuzzy_subsets(+Subsets, -AddedSubsets)
Adds a list of Subsets to the current list of subsets stored in the BPL flags, and returns a list with the subsets that were not already in them. Each subset must be defined with a list following this syntax: [Domain, [SubsetDefinition]] (note that this is the same syntax used by the fuzzy_set/2 BPL directive).
  804add_fuzzy_subsets([], []).
  805
  806add_fuzzy_subsets([[Domain, [SubsetDefinition]]|MoreSubsets], AddedSubsets) :-
  807	% Checks if this subset is already defined
  808	flags:get_bpl_flag(fuzzy_subsets(Domain, DomainSubsets)),
  809	(member(SubsetDefinition, DomainSubsets) ->
  810		% Subset is alredy defined
  811		true,
  812		Added = []
  813	;
  814		% Adds the new subset to the lists of subsets of the domain
  815		append(DomainSubsets, [SubsetDefinition], NewDomainSubsets),
  816		Added = [[Domain, [SubsetDefinition]]],
  817		% Updates the fuzzy subsets of the domain
  818		flags:remove_bpl_flag(fuzzy_subsets(Domain, DomainSubsets)),
  819		flags:add_bpl_flag(fuzzy_subsets(Domain, NewDomainSubsets))
  820	),
  821	% Adds the remaining fuzzy subsets
  822	add_fuzzy_subsets(MoreSubsets, MoreAdded),
  823	append(Added, MoreAdded, AddedSubsets).
  824
  825
  826
  827%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  828% Auxiliary dynamic predicates
  829%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Auxiliary dynamic predicate used by assert_translator_scanner/1 and retract_translator_scanner/1 that store the prefix that must be appended to the predicate names.
  839:- dynamic program_prefix/1.
Auxiliary dynamic predicate used by assert_translator_scanner/1 and retract_translator_scanner/1 that store the list of equations of the main proximity/similarity relation.
  849:- dynamic equations/1.