1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    2% Bousi-Prolog interpreter
    3
    4:- module(evaluator, [
    5		load_tpl/1,             % +File
    6		load_tpls/1,            % +File
    7		solve_goal/1,           % :Goal
    8		get_sim_equations/1,    % -Equations
    9		add_sim_equations/1,    % +Equations
   10    update_sim_equations/1, % +Equations
   11    build_block_equations/2 % +Equations, -BlockEquations
   12%    retract_all_dyn_predicates/0
   13   ]).   14
   15:- use_module(directives).   16:- use_module(utilities).   17:- use_module(flags).   18:- use_module(library(ordsets)).   19
   20% The following libraries aren't used by this module, but are imported
   21% in case they are needed by Bousi-Prolog programs or queries
   22:- use_module(library(help)).   23:- use_module(library(lists)).   24:- use_module(library(readutil)).   25:- use_module(library(statistics)).   26
   27%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   28
   29:- set_prolog_flag(double_quotes, codes).   30
   31
   32%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   33% Public predicates
   34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 load_tpl(+File)
Loads a translated Bousi-Prolog (TPL) file directly into memory, unloading the last file loaded with this predicate first. If File is an empty string, the current loaded file will be removed from the database but no file will be loaded afterwards.
   45load_tpl(File) :-
   46  retract_all_dyn_predicates,
   47% Moved to bplShell:load_file/2
   48% 	% Removes all dynamic predicates from the previous loaded program
   49% 	retractall(sim(_, _, _)),
   50% 	retractall(sim(_, _, _, _)),
   51% 	retractall(lEqThan(_, _, _)),
   52% 	retractall(gEqThan(_, _, _)),
   53% 	retractall(frel1(_, _, _)),
   54% 	retractall(frel2(_, _, _)),
   55% 	retractall(frel3(_, _, _)),
   56	(current_predicate(unload_file/1) ->
   57		% The unload_file/1 predicate is available only in SWI-Prolog
   58		% 5.10.0 and later
   59		current_file(OldFile),
   60		(OldFile \== '' ->
   61			unload_file(OldFile)
   62		;
   63			true
   64		),
   65		retract(current_file(OldFile)),
   66		assert(current_file(File))
   67	;
   68		% User-defined predicates can't be erased using retractall/1
   69		% because they're not dynamic; as a result, SWI-Prolog will
   70		% show a warning if the same program is loaded twice
   71		true
   72	),
   73	(File \== '' ->
   74		% Loads the new program
   75		consult(File)
   76	;
   77		% Initializes the symmetric fuzzy relations so they can be
   78		% used without having a program loaded
   79		assert(sim(X, X, 1.0)),
   80		assert(frel1(X, X, 1.0)),
   81		assert(frel2(X, X, 1.0)),
   82		assert(frel3(X, X, 1.0))
   83	).
   84
   85retract_all_dyn_predicates :-
   86	% Removes all dynamic predicates from the previous loaded program
   87	retractall(sim(_, _, _)),
   88	retractall(sim(_, _, _, _)),
   89	retractall(lEqThan(_, _, _)),
   90	retractall(gEqThan(_, _, _)),
   91	retractall(frel1(_, _, _)),
   92	retractall(frel2(_, _, _)),
   93	retractall(frel3(_, _, _)).
 load_tpls(+File)
Loads a translated Bousi-Prolog state (TPLS) file directly into memory, unloading the last file loaded with this predicate first. If File is an empty string, the current loaded file will be removed from the database but no file will be loaded afterwards.
  102load_tpls(File) :-
  103	current_file(OldFile),
  104	(OldFile \== '' ->
  105		unload_file(OldFile)
  106	;
  107		true
  108	),
  109	(File \== '' ->
  110		% Loads the new program
  111		consult(File)
  112	;
  113		true
  114	).
 solve_goal(:Goal)
Executes the specified Goal under this module, using the rules and relations of the currently loaded program. Formally, this predicate succeeds if there's a refutation for Goal with a certain approximation degree.
  125solve_goal(Goal) :-
  126	catch((
  127		Goal
  128	% (catcher)
  129	), error(existence_error(procedure, Predicate), context(Context, Extra)), (
  130		% When an undefined predicate is called, SWI-Prolog throws an
  131		% exception that contains the internal name of some predicates
  132		% (e.g. given "undefined/2", the exception message will include
  133		% "evaluator:prefix_undefined/3"); here we get the actual names
  134		% of the predicates and throws a new exception with them		
  135		get_actual_predicate_definition(Predicate, ActualPredicate),
  136		get_actual_predicate_definition(Context, ActualContext),
  137		throw(error(existence_error(procedure, ActualPredicate), context(ActualContext, Extra)))
  138	)).
 get_sim_equations(-Equations)
Unifies Equations with the list of currently defined proximity/similarity equations, that is, sim/3 terms. Equations are ordered
  148get_sim_equations(Equations) :-
  149%	findall(sim(Sym1, Sym2, Degree), sim(Sym1, Sym2, Degree), Equations).
  150	nf_setof(sim(Sym1, Sym2, Degree), sim(Sym1, Sym2, Degree), Equations).
 nf_setof(+Template, +Goal, -Set)
Non-failing setof
  157nf_setof(X,Y,Z) :-
  158  setof(X,Y,Z),
  159  !.
  160  
  161nf_setof(_,_,[]).
 add_sim_equations(+Equations)
Asserts a list of proximity/similarity equations, that is, sim/3 terms. Equations that are already defined or aren't sim/3 terms won't be added to the database.
  172add_sim_equations(Equations) :-
  173  add_sim_equations(Equations, _Added).
 add_sim_equations(+Equations, -Added)
As add_sim_equations, but adding a flag signalling whether there was anyone actually added. If so, Added=yes, else Added=no
  182add_sim_equations([], Added) :-
  183  var(Added),
  184  !,
  185  Added = no.
  186  
  187add_sim_equations([], _Added). % If not a var, _Added should be 'yes'
  188
  189add_sim_equations([sim(Sym1, Sym2, Value)|MoreEquations], Added) :-
  190	sim(Sym1, Sym2, OldValue),
  191	OldValue >= Value,
  192	% If the equation is already defined with a greater or equal degree,
  193	% no need to define it again
  194	!,
  195	add_sim_equations(MoreEquations, Added).
  196
  197add_sim_equations([sim(Sym1, Sym2, Value)|MoreEquations], Added) :-
  198	% Equation isn't defined, so it must be asserted
  199	!,
  200	assert(sim(Sym1, Sym2, Value)),
  201	Added = yes,
  202	add_sim_equations(MoreEquations, Added).
  203
  204add_sim_equations([_|MoreEquations], Added) :-
  205	% Equation which is not a sim/3 term
  206	!,
  207	add_sim_equations(MoreEquations, Added).
 update_sim_equations(+Equations)
Asserts a list of proximity/similarity equations sim/3 using add_sim_equations, and recomputes sim/4 for the weak unification algorithm a3. Closures for sim/3 are not computed.
  219update_sim_equations(Equations) :-
  220  update_sim_equations(Equations, _Updated).
 update_sim_equations(+Equations, +Updated)
As update_sim_equations, but adding a flag signalling whether there was anyone updated. If so, Updated=yes, else Updated=no
  229update_sim_equations(Equations, Updated) :-
  230  flags:bpl_flags(weak_unification(a3)),
  231  !,
  232  add_sim_equations(Equations, Updated),
  233  retractall(sim(_,_,_,_)),
  234	build_block_equations(Equations, _BlockEquations).
  235
  236update_sim_equations(Equations, Updated) :-
  237  add_sim_equations(Equations, Updated).
  238
  239
  240
  241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  242% Building block equations
  243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 build_block_equations(+Equations, -BlockEquations)
If the flag weak_unification is set to 'a3', it builds the corresponding block equations from the input list of sim equations. Otherwise, it returns no block equations. The block equations can be built either with Prolog code (flag ext_block_equs set to false) or C code (flag set to true) The relation sim/3 is expected to be already generated and stored in the dynamic database. The relation sim/4 (for the weak unification algorithm a3) is not expected to be stored in the dynamic database. Upon completion of this predicate, both relations sim/3 and sim/4 will be stored in the dynamic database.
  261build_block_equations(Equations, BlockEquations) :-
  262	flags:get_bpl_flag(weak_unification('a3')),
  263	flags:get_bpl_flag(ext_block_equs('false')),
  264	!,
  265  evaluator:add_sim_equations(Equations),
  266  evaluator:sim(F,T,D),
  267  var(F),
  268  retract(evaluator:sim(F,T,D)),
  269  gen_rb(BlockEquations),
  270%  retractall(evaluator:sim(_,_,_)),
  271  assert(evaluator:sim(F,T,D)).
  272 
  273% build_block_equations(Equations, BlockEquations) :-
  274% 	flags:get_bpl_flag(weak_unification('a3')),
  275% %	flags:get_bpl_flag(ext_block_equs('true')),
  276% 	!,
  277% 	findall(sim(X,Y,D), member(sim(X,Y,D), Equations), SimEquations),
  278% %	copy_term(Equations, CopyEquations), % WARNING: Workaround to avoid instantiations in Equations due to foreign:ext_block_equs. Remove the copy when fixed
  279% %	get_sim_equations(StoredEquations),
  280% %	append(StoredEquations, CopyEquations, AllEquations),
  281% %	append(StoredEquations, SimEquations, AllEquations),
  282% 	foreign:ext_block_equs(0, SimEquations, sim, BlockEquations),
  283%   maplist(assert, BlockEquations).
  284
  285build_block_equations(Equations, BlockEquations) :-
  286	flags:get_bpl_flag(weak_unification('a3')),
  287%	flags:get_bpl_flag(ext_block_equs('true')),
  288	!,
  289	% Get all sim equations from Equations, which may have other relations, such as frel1,2,3
  290 	nf_setof(sim(X,Y,D), member(sim(X,Y,D), Equations), SimEquations), 
  291	copy_term(SimEquations, CopyEquations), % WARNING: Workaround to avoid instantiations in Equations due to foreign:ext_block_equs. Remove the copy when fixed
  292	get_sim_equations(StoredEquations),
  293	ord_union(StoredEquations, CopyEquations, AllEquations),
  294	foreign:ext_block_equs(0, AllEquations, sim, BlockEquations),
  295  maplist(assert, BlockEquations).
  296
  297build_block_equations(_Equations, []).
  298
  299	
  300%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  301% Generating the Extended Proximity Relation
  302%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 gen_rb(-BlockEquations)
Generates the extended proximity relation RB from the proximity relation R already asserted. Notice that the proximity relation R is implemented with the predicate sim/3 and the extended proximity relation RB is implemented with the predicate sim/4. sim/3 is expected to be in the dynamic database, whereas sim/4 do not. sim/4 is asserted with gen_rb.
  314gen_rb(BlockEquations) :-
  315  setof(F,T^D^(evaluator:sim(F,T,D)),G),  % Nodes
  316  allMaxCliques(G,LC),
  317  build_ctrs(LC,Ctrs),        % Build annotations Symbol:Block as an ordered list
  318  gen_entries(Ctrs),
  319  setof(sim(F,T,B,D),evaluator:sim(F,T,B,D),BlockEquations),
  320  !.
  321  
  322gen_rb([]).
  323
  324                          
  325build_ctrs(LC,Cout) :-
  326  build_ctrs(LC,1,[],Cout).    
  327   
  328build_ctrs([],_B,Cin,Cin).
  329build_ctrs([Cs|LC],B,Cin,Cout) :-
  330  ctrs_from_block(Cs,B,Cin,Cin1),
  331  B1 is B+1,
  332  build_ctrs(LC,B1,Cin1,Cout).
  333  
  334ctrs_from_block([],_B,Cin,Cin).
  335ctrs_from_block([C|Cs],B,Cin,Cout) :-
  336  ord_union([C:B],Cin,Cin1), 
  337  ctrs_from_block(Cs,B,Cin1,Cout).
  338
  339ord_ctr_member(X,[X|_Xs]). 
  340ord_ctr_member(X:B,[Y:_|Xs]) :-
  341  X@>=Y,
  342  ord_ctr_member(X:B,Xs). 
  343  
  344gen_entries(Ctrs) :-
  345  evaluator:sim(F,T,D),
  346  ord_ctr_member(F:B,Ctrs),
  347  ord_ctr_member(T:B,Ctrs),
  348  assert(evaluator:sim(F,T,B,D)),
  349  fail.
  350gen_entries(_Ctrs).
  351
  352
  353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  354% Maximal cliques from the graph defined by the 'sim' relation
  355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  356
  357/****************************************************************************
  358****************************************************************************/
  359
  360
  361/****************************************************************************
  362BronKerbosch2(R,P,X):
  363    if P and X are both empty:
  364         report R as a maximal clique 
  365    choose a pivot vertex u in P ? X 
  366    for each vertex v in P \ N(u):
  367         BronKerbosch2(R ? {v}, P ? N(v), X ? N(v)) 
  368         P := P \ {v}
  369         X:=X ? {v}
  370*****************************************************************************/
  371
  372allMaxCliques(LC) :-
  373  setof(F,T^D^(evaluator:sim(F,T,D)),Fs),
  374  allMaxCliques(Fs,LC).
  378allMaxCliques(G,LC) :-
  379%  list_to_ord_set(G,OG),         % Use this alternative when
  380%  setof(C, maxClique(OG,C), LC). % G is not expected to be ordered
  381  setof(C, maxClique(G,C), LC).
  384g(LC) :- allMaxCliques([1,2,3,4,5,6],LC).
  388maxClique(G, C) :-
  389  maxClique(G,[],[], C).
  392/*
  393Finds the maximal cliques that include all of the vertices in R, some of the 
  394vertices in P, and none of the vertices in X. In each call to maxClique/4, 
  395P and X are disjoint sets whose union consists of those vertices that form 
  396cliques when added to R. 
  397When P and X are both empty there are no further elements that can be added to R, 
  398so R is a maximal clique and maxClique/4 outputs R.
  399
  400A is an accumulator parameter where R is built step by step.
  401
  402Notice: maxClique/4 implements BronKerbosch2 but with variations; for instance, the 
  403instructions P := P \ {v} and X:=X ? {v} are not considered; perhaps, by this reason 
  404the implementation is more inefficient, obtaining many redundant answers. 
  405*/
  410maxClique([],[],R,OR) :-
  411  !, % FSP
  412  list_to_ord_set(R,OR).
  413maxClique(P,X,A,R) :-
  414  ord_union(P,X,PX), 
  415  pivot(PX,U),  
  416  neighborSet(U,NU), 
  417  ord_subtract(P,NU,DP), 
  418  member(V,DP), 
  419  neighborSet(V,NV), 
  420  ord_intersection(P,NV,PNV), 
  421  ord_intersection(X,NV,XNV), 
  422  maxClique(PNV,XNV,[V|A],R). 
  423
  424
  425% Neighbor set of vertex V in G
  426neighborSet(V,NV) :-
  427  setof(N, D^(evaluator:sim(V,N,D)), NV). % Explicit Symmetry
  428%  setof(N, D^(sim(V,N,D) ; sim(N,V,D)), NV). % Implicit Symmetry
  429
  430
  431% Neighbor set of vertex V in the set PX
  432% NOT USED.
  433% neighborSet(V,PX,NVPX) :-
  434%   setof(N, D^sim(V,N,D), NV), 
  435%   intersect(PX,NV, NVPX).
  436
  437
  438%%pivot(PX,U)
  439%% IMPORTANT: We choose a pivot U that maximizes N(U), i.e., the neighbor 
  440%% set of U.
  441%% 
  442pivot(PX,U) :-
  443  pivot(PX,0,[],U).
  444  
  445pivot([],_,[A],A).
  446pivot([V|Vs],AN,_,U) :-
  447  neighborSet(V,NV), 
  448  length(NV,L), 
  449  L>AN, 
  450  !, 
  451  pivot(Vs,L,[V],U).
  452pivot([_|Vs],AN,[A],U) :-
  453  pivot(Vs,AN,[A],U).
  454
  455/*****************************************
  456%% IMPORTANT: When we follow Tomita's option, consisting in
  457%% maximizing P ? N(U), this program does not work. Do not ask why.
  458%%
  459%%pivot(PX,P,U)
  460%% 
  461pivot(PX,P,U) :- pivot(PX,P,0,[],U).
  462pivot([],_,_,[A],A).
  463pivot([V|Vs],P,AN,_,U) :- neighborSet(V,NVP), %neighborSet(V,P,NVP),
  464                    length(NVP,L), L>AN, !, pivot(Vs,P,L,[V],U).
  465pivot([_|Vs],P,AN,[A],U) :- pivot(Vs,P,AN,[A],U).
  466*******************************************/
  467
  468
  469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  470% Weak unification algorithm 'a1'. Used for bpl_flag(weak_unification(a1))
  471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 weak_unify_a1(?Term1, ?Term2, +Lambda, ?Degree)
Unifies Term1 and Term2 using unification by proximity/similarity and returns the approximation Degree in which both terms unify. Lambda is the lower bound allowed for the approximation degree of the weak unifications.
  482weak_unify_a1(Atomic1, Atomic2, Lambda, Degree) :-
  483	% Atom (constant) unification
  484	atomic(Atomic1), atomic(Atomic2), !,
  485	sim(Atomic1, Atomic2, Degree),
  486	Degree >= Lambda.
  487
  488weak_unify_a1(Term1, Term2, Lambda, Degree) :-
  489	% Term decomposition
  490	compound(Term1), compound(Term2), !,
  491	Term1 =.. [Functor1|Args1],
  492	Term2 =.. [Functor2|Args2],
  493	length(Args1, Arity),
  494	length(Args2, Arity),
  495	sim(Functor1, Functor2, DegreeFunctor), 
  496	DegreeFunctor >= Lambda,
  497	weak_unify_args_a1(Args1, Args2, Lambda, DegreeArgs),
  498%	Degree is min(DegreeFunctor, DegreeArgs).
  499  t_norm_op(DegreeFunctor, DegreeArgs, Degree).
  500
  501weak_unify_a1(Term, Variable, _Lambda, 1) :-
  502	% Term/variable swap + Variable removal
  503	nonvar(Term), var(Variable), !,
  504	Variable = Term.
  505
  506weak_unify_a1(Variable, Term, _Lambda, 1) :-
  507	% Variable removal / Trivial equation removal
  508	var(Variable),
  509	Variable = Term.
 weak_unify_args_a1(?Args1, ?Args2, +Lambda, ?Degree)
Checks if the terms in the Args1 and Args2 lists can unify one with each other and returns the minimum approximation Degree of the unifications.
  519weak_unify_args_a1([], [], _Lambda, 1).
  520
  521weak_unify_args_a1([Arg1|MoreArgs1], [Arg2|MoreArgs2], Lambda, Degree) :-
  522	weak_unify_a1(Arg1, Arg2, Lambda, DegreeArg),
  523	weak_unify_args_a1(MoreArgs1, MoreArgs2, Lambda, DegreeMoreArgs),
  524  t_norm_op(DegreeArg, DegreeMoreArgs, Degree).
  525%	Degree is min(DegreeArg, DegreeMoreArgs).
  526
  527
  528	
  529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  530% Weak unification algorithm 'a2'
  531%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  532
  533
  534% We declare the proximity constraint operator. We use it as a notation for proximity 
  535% constraints. A proximity constraint (of level L), 'a -- b', is a non-ordered pair of 
  536% symbols {a,b}, holding: sim(a, b, D) with D >= L.
  537:- op(750, yfx, '--').  538
  539:- dynamic '--'/2.  540
  541
  542%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  543%% weak_unify_a2(?Term1, ?Term2, +Lambda, +Cin, -Cout, ?Degree)
  544%
  545%     Unifies Term1 and Term2 using unification by proximity/similarity
  546%     and returns the approximation Degree in which both terms unify.
  547%     Lambda is the lower bound allowed for the approximation degree
  548%     of the weak unifications. Cin is the input constraint store of 
  549%     proximity constraints, and Cout the output constraint store.
  550
  551weak_unify_a2(Atomic1, Atomic2, Lambda, Cin, Cout, Degree) :-
  552  % Atom (constant) unification
  553  atomic(Atomic1), 
  554  atomic(Atomic2), 
  555  !,
  556  (Atomic1==Atomic2
  557   ->
  558    Degree=1,
  559    Cout=Cin
  560   ;
  561    unification_degree_a2(Atomic1, Atomic2, Degree),
  562    Degree >= Lambda,
  563    sat_a2(Atomic1--Atomic2, Cin, Cout)
  564  ).
  565
  566weak_unify_a2(Term1, Term2, Lambda, Cin, Cout, Degree) :-
  567  % Term decomposition
  568  compound(Term1), 
  569  compound(Term2), 
  570  !,
  571  Term1 =.. [Functor1|Args1],
  572  Term2 =.. [Functor2|Args2],
  573  length(Args1, Arity),
  574  length(Args2, Arity),
  575  (Functor1==Functor2
  576   ->
  577    Cin1=Cin,
  578    DegreeFunctor=1
  579   ;
  580    unification_degree_a2(Functor1, Functor2, DegreeFunctor),
  581    DegreeFunctor >= Lambda,
  582    sat_a2(Functor1--Functor2, Cin, Cin1)
  583  ),
  584  weak_unify_args_a2(Args1, Args2, Lambda, Cin1, Cout, DegreeArgs),
  585%  Degree is min(DegreeFunctor, DegreeArgs).
  586  t_norm_op(DegreeFunctor, DegreeArgs, Degree).
  587
  588weak_unify_a2(Term, Variable, _Lambda, Cin, Cin, 1) :-
  589  % Term/variable swap + Variable removal
  590  nonvar(Term), 
  591  var(Variable), 
  592  !,
  593%  occur_check(Variable, Term),
  594  Variable = Term.
  595
  596weak_unify_a2(Variable, Term, _Lambda, Cin, Cin, 1) :-
  597  % Variable removal / Trivial equation removal
  598  var(Variable),
  599%  occur_check(Variable, Term),
  600  Variable = Term.
 weak_unify_args_a2(?Args1, ?Args2, +Lambda, +Cin, -Cout, ?Degree)
Checks if the terms in the lists Args1 and Args2 can unify one with each other and returns the minimum approximation Degree of the unifications.
  609weak_unify_args_a2([], [], _Lambda, Cin, Cin, 1).
  610
  611weak_unify_args_a2([Arg1|MoreArgs1], [Arg2|MoreArgs2], Lambda, Cin, Cout, Degree) :-
  612  weak_unify_a2(Arg1, Arg2, Lambda, Cin, Cin1, DegreeArg),
  613  weak_unify_args_a2(MoreArgs1, MoreArgs2, Lambda, Cin1, Cout, DegreeMoreArgs),
  614%  Degree is min(DegreeArg, DegreeMoreArgs).
  615  t_norm_op(DegreeArg, DegreeMoreArgs, Degree).
  616
  617% occur_check(Variable, Term) :-
  618%   term_variables(Term, Variables),
  619%   \+ memberchk_eq(Variable,Variables). % Needs library hprolog.pl
 unification_degree_a2(Atomic1, Atomic2, Degree)
  623unification_degree_a2(Atomic, Atomic, 1.0). % Don't lookup and assume true for all the data universe for a reflexive relation
  624
  625unification_degree_a2(Atomic1, Atomic2, Degree) :-
  626  sim(Atomic1, Atomic2, Degree).
  627
  628
  629
  630%%%
  631% ESTA SOLUCION NO HACE USO DEL LAMBDA CUT PARA NO TENER QUE INTRODUCIR LAS ENTRADAS 
  632% DE LA RELACION DE PROXIMIDAD ENTRE ELEMENTOS CON GRADO DE PROXIMIDAD 0
  633
  634
  635
  636%%%%%%%%%%%%%%%
  637%% sat_a2_ctrs(C): Checks if a set of proximity constraints C is consistent. That is, if
  638% there is no divergent paths in the graph of proximity constraints. A path between the
  639% vertexes X and Y is divergent if X is close to Y with degree D (sim(X,Y,D)) and D is 
  640% less than the Lambda-cut (D<L).
  641%%% NOTICE THAT  for two elements to belong to the same Lambda-block it is necessary
  642% that sim(X,Y,D) and D>=L. Then, if sim(X,Y,D) and D<L is because X belongs to a block 
  643% and Y to another. This is signaling out that an inner element in the divergent path
  644% is playing two roles.
  645%%% ALSO NOTICE THAT if there is no divergent paths, the condition 
  646%             (ctrs_path(X,Y), sim(X,Y,D), D<L)
  647% generates the transitive closure of the relation defined by the set of proximity 
  648% constraints by backtracking. On the other hand, it is not necessary to compute the 
  649% whole transitive closure, it suffices to detect the first divergent path and fail.
  650
  651sat_a2(E1--E2, Cin, Cout) :- 
  652	uniPCS([E1--E2], Cin, Cout), sat_a2_ctrs(Cout). 
  653
  654sat_a2_ctrs(C) :- 
  655	load_ctrs(C),
  656	((ctrs_path(X,Y), \+sim(X,Y,_D)) %%(ctrs_path(X,Y), sim(X,Y,D), D<L) %%
  657	->
  658	clear_ctrs,
  659	false
  660	;
  661	clear_ctrs,
  662	true	
  663	).
  664
  665
  666
  667
  668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  669%%       AUXILIARY PREDICATES
  670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  671
  672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  673%%%%%%%%%%%%%%%  PROXIMITY CONSTRAINT SET (PCS) PROCESSING  %%%%%%%%%%%%%%%%%%%%
  674
  675% Member of a block constraint set
  676membPCS(S1--S2, [S1--S2|_]). 
  677membPCS(S1--S2, [S2--S1|_]). 
  678membPCS(S1--S2, [_|L]) :- membPCS(S1--S2, L).
  679
  680% Subset of a block constraint set
  681subPCS([], _).
  682subPCS([S1--S2|R], C) :- membPCS(S1--S2, C), subPCS(R, C).
  683
  684% 
  685equalPCS(A, B) :- subPCS(A, B), subPCS(B, A).
  686
  687% Union	
  688uniPCS([], C, C).
  689uniPCS([S1--S2|R], C2, C) :- membPCS(S1--S2, C2), !, uniPCS(R, C2, C).
  690uniPCS([S1--S2|R], C2, [S1--S2|C]) :- uniPCS(R, C2, C).
  691
  692% Intersection
  693interPCS([], _, []).
  694interPCS([S1--S2|R], C2, [S1--S2|C]) :- membPCS(S1--S2, C2), !, interPCS(R, C2, C).
  695interPCS([_|R], C2, C) :- interPCS(R,C2, C).
  696
  697
  698
  699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  700%%%%%%%%%%%%%%%           CONSTRAINT GRAPHS                %%%%%%%%%%%%%%%%%%%%
  701
  702%%%%%%%%%%%%%%%
  703%% load_ctrs(C): asserts the list of proximity constraints C.
  704load_ctrs([]).
  705load_ctrs([X--Y|Cs]) :- assert(X--Y), assert(Y--X), load_ctrs(Cs).
  709clear_ctrs:- retractall(_X--_Y).
  710
  711
  712%%%%%%%%%%%%%%%
  713%% ctrs_path(X,Y): True if there is a path between the vertexes X and Y in the graph of 
  714%% proximity constraints. X must be different from Y.
  715ctrs_path(X,Y) :- ctrs_path(X,Y, _).
  716
  717ctrs_path(X,Y, P) :- ctrs_path(X,Y,[X],P).
  718
  719ctrs_path(X,Y, A, [Y|A]) :- X--Y, \+member(Y,A). 
  720ctrs_path(X,Y, A, P) :- X--Z, \+member(Z,A), ctrs_path(Z,Y,[Z|A],P).
  721
  722
  723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  724%%%%%%%%%%%%%%%           PROXIMITY RELATION              %%%%%%%%%%%%%%%%%%%%
  725%% clear_sim: retracts all the loaded proximity relation entries.
  726% clear_sim:- retractall(sim(_X,_Y,_D)).
  727
  728
  729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  730% Weak unification algorithm 'a3'. Used for bpl_flag(weak_unification(a3))
  731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 weak_unify_a3(?Term1, ?Term2, +Lambda, +Cin, -Cout, ?Degree)
Unifies Term1 and Term2 using unification by proximity/similarity and returns the approximation Degree in which both terms unify. Lambda is the lower bound allowed for the approximation degree of the weak unifications. Cin is the input constraint store of block constraints, and Cout the output constraint store.
  742weak_unify_a3(Atomic1, Atomic2, Lambda, Cin, Cout, Degree) :-
  743  % Atom (constant) unification
  744  atomic(Atomic1), 
  745  atomic(Atomic2), 
  746  !,
  747  (Atomic1==Atomic2
  748   ->
  749    Degree=1.0,
  750    Cout=Cin
  751   ;
  752    unification_degree_a3(Atomic1, Atomic2, Block, Degree),
  753    Degree >= Lambda,
  754    sat_a3([Atomic1:Block, Atomic2:Block], Cin, Cout)
  755  ).
  756
  757weak_unify_a3(Term1, Term2, Lambda, Cin, Cout, Degree) :-
  758  % Term decomposition
  759  compound(Term1), 
  760  compound(Term2), 
  761  !,
  762  Term1 =.. [Functor1|Args1],
  763  Term2 =.. [Functor2|Args2],
  764  length(Args1, Arity),
  765  length(Args2, Arity),
  766  (Functor1==Functor2
  767   ->
  768    Cin1=Cin,
  769    DegreeFunctor=1.0
  770   ;
  771    unification_degree_a3(Functor1, Functor2, Block, DegreeFunctor),
  772    DegreeFunctor >= Lambda,
  773    sat_a3([Functor1:Block, Functor2:Block], Cin, Cin1)
  774  ),
  775  weak_unify_args_a3(Args1, Args2, Lambda, Cin1, Cout, DegreeArgs),
  776%  Degree is min(DegreeFunctor, DegreeArgs). 
  777  t_norm_op(DegreeFunctor, DegreeArgs, Degree).
  778  
  779weak_unify_a3(Term, Variable, _Lambda, Cin, Cin, 1.0) :-
  780  % Term/variable swap + Variable removal
  781  nonvar(Term), 
  782  var(Variable), 
  783  !,
  784  Variable = Term.
  785  
  786weak_unify_a3(Variable, Term, _Lambda, Cin, Cin, 1.0) :-
  787  % Variable removal / Trivial equation removal
  788  var(Variable),
  789  Variable = Term.
 weak_unify_args_a3(?Args1, ?Args2, +Lambda, +Cin, -Cout, ?Degree)
Checks if the terms in the lists Args1 and Args2 can unify one with each other and returns the minimum approximation Degree of the unifications.
  799weak_unify_args_a3([], [], _Lambda, Cin, Cin, 1.0).
  800
  801weak_unify_args_a3([Arg1|MoreArgs1], [Arg2|MoreArgs2], Lambda, Cin, Cout, Degree) :-
  802  weak_unify_a3(Arg1, Arg2, Lambda, Cin, Cin1, DegreeArg),
  803  weak_unify_args_a3(MoreArgs1, MoreArgs2, Lambda, Cin1, Cout, DegreeMoreArgs),
  804%  Degree is min(DegreeArg, DegreeMoreArgs).
  805  t_norm_op(DegreeArg, DegreeMoreArgs, Degree).
 unification_degree_a3(?Atomic1, ?Atomic2, ?Block, ?Degree)
Relates two atoms Atomic1 and Atomic2 with their block and approximation degree as stated in the sim relation. Since reflexivity is not explicitly included in sim, this predicate returns 1.0 as the unification degree of two equal atoms for any block.
  817unification_degree_a3(Atomic, Atomic, _Block, 1.0). % Don't lookup and assume true for all the data universe for a reflexive relation
  818
  819unification_degree_a3(Atomic1, Atomic2, Block, Degree) :-
  820  sim(Atomic1, Atomic2, Block, Degree).
 sat_a3(+Constraints, +InConstraints, +OutConstraints)
Checks the satisfiabality of Constraints w.r.t. InConstraints. If so, it returns the union of Constraints and InConstraints, otherwise it fails.
  830sat_a3([], Cin, Cin).
  831sat_a3([Ctr|Ctrs], Cin, Cout) :-
  832  sat_a3_ctr(Ctr, Cin, Cin1),
  833  sat_a3(Ctrs, Cin1, Cout).
  834
  835sat_a3_ctr(Symbol:Block, Cin, Cin) :-
  836  get_assoc(Symbol, Cin, Block1),
  837  !,
  838  Block=Block1.
  839sat_a3_ctr(Symbol:Block, Cin, Cout) :-
  840  put_assoc(Symbol, Cin, Block, Cout).
  841
  842
  843
  844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  845% Unification by proximity/similarity
  846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 unify_a1(?Term1, ?Term2, ?Degree)
Algorithm 'a1'. Unifies Term1 and Term2 using unification by proximity/similarity and returns the approximation Degree in which both terms unify.
  856unify_a1(Term1, Term2, Degree) :-
  857	flags:get_bpl_flag(lambda_cut(Lambda)),
  858	weak_unify_a1(Term1, Term2, Lambda, Degree).
 unify_a2(?Term1, ?Term2, +Cin, -Cout, ?Degree)
Algorithm 'a2'. Unifies Term1 and Term2 using unification by proximity with algorithm a2, and returns the approximation Degree in which both terms unify.
  869unify_a2(Term1, Term2, Cin, Cout, Degree) :-
  870	flags:get_bpl_flag(lambda_cut(Lambda)),
  871	weak_unify_a2(Term1, Term2, Lambda, Cin, Cout, Degree).
  872
  873unify_a2(Term1, Term2, Degree) :-
  874  parser:init_ctr_store([Cin]),
  875  unify_a2(Term1, Term2, Cin, _Cout, Degree).
 unify_a3(?Term1, ?Term2, +Cin, -Cout, ?Degree)
Algorithm 'a2'. Unifies Term1 and Term2 using unification by proximity with algorithm a2, and returns the approximation Degree in which both terms unify.
  886unify_a3(Term1, Term2, Cin, Cout, Degree) :-
  887	flags:get_bpl_flag(lambda_cut(Lambda)),
  888	weak_unify_a3(Term1, Term2, Lambda, Cin, Cout, Degree).
  889
  890unify_a3(Term1, Term2, Degree) :-
  891  parser:init_ctr_store([Cin]),
  892  unify_a3(Term1, Term2, Cin, _Cout, Degree).
 unify_a1(?Term1, ?Term2, +Comparer, ?Value) is semidet
Unifies Term1 and Term2 using unification by proximity/similarity with algorithm a1. Succeeds only if the resulting approximation degree satisfies the expression "degree Comparer Value" (for example, "degree > 0.5"). Comparer can be any Prolog arithmetic comparison operator (=:=, =\=, >=, =<, >, <) or the unification operator (in the latter case, Value will be unified with the approximation degree).
  907unify_a1(Term1, Term2, Comparer, Value) :-
  908	unify_a1(Term1, Term2, Degree),
  909	apply(Comparer, [Degree, Value]),
  910	!.
 unify_a2(?Term1, ?Term2, +Comparer, ?Value) is semidet
Unifies Term1 and Term2 using unification by proximity/similarity with algorithm a2.
  918unify_a2(Term1, Term2, Comparer, Value) :-
  919	unify_a2(Term1, Term2, Degree),
  920	apply(Comparer, [Degree, Value]),
  921	!.
 unify_a3(?Term1, ?Term2, +Comparer, ?Value) is semidet
Unifies Term1 and Term2 using unification by proximity/similarity with algorithm a3.
  929unify_a3(Term1, Term2, Comparer, Value) :-
  930	unify_a3(Term1, Term2, Degree),
  931	apply(Comparer, [Degree, Value]),
  932	!.
 unify_arguments_a1(?Problems)
Solves several unification Problems using the weak unification algorithm a1. Problems must be a list containing sublists with three items: two terms and a variable where the approximation degree of the terms will be stored. If any of the weak unifications fail, the whole predicate will fail.
  944unify_arguments_a1([]).
  945
  946unify_arguments_a1([[Term1, Term2, Degree]|MoreProblems]) :-
  947	unify_a1(Term1, Term2, Degree),
  948	unify_arguments_a1(MoreProblems).
 unify_arguments_a2(?Problems)
Solves several unification Problems using the weak unification algorithm a2.
  956unify_arguments_a2([]).
  957
  958unify_arguments_a2([[Term1, Term2, Cin, Cout, Degree]|MoreProblems]) :-
  959  unify_a2(Term1, Term2, Cin, Cout, Degree),
  960  unify_arguments_a2(MoreProblems).
 unify_arguments_a3(?Problems)
Solves several unification Problems using the weak unification algorithm a2.
  968unify_arguments_a3([]).
  969
  970unify_arguments_a3([[Term1, Term2, Cin, Cout, Degree]|MoreProblems]) :-
  971  unify_a3(Term1, Term2, Cin, Cout, Degree),
  972  unify_arguments_a3(MoreProblems).
  973
  974
  975
  976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  977% Extension of user-defined fuzzy relations to terms
  978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 e_frel1(?Term1, ?Term2, ?Degree) is nondet
Compares Term1 and Term2 using '~1~' fuzzy relation and returns the approximation Degree of the result (if it's greater than 0).
  987e_frel1(Term1, Term2, Degree) :-
  988	flags:get_bpl_flag(lambda_cut(Lambda)),
  989	compare_terms(frel1, Term1, Term2, Lambda, Degree).
 e_frel1(?Term1, ?Term2, +Comparer, ?Value) is semidet
Compares Term1 and Term2 using '~1~' fuzzy relation and succeeds only if the resulting approximation degree satisfies the expression "degree Comparer Value" (for example, "degree > 0.5"). Comparer can be any Prolog arithmetic comparison operator (=:=, =\=, >=, =<, >, <) or the unification operator (in the latter case, Value will be unified with the approximation degree).
 1002e_frel1(Term1, Term2, Comparer, Value) :-
 1003	e_frel1(Term1, Term2, Degree),
 1004	apply(Comparer, [Degree, Value]),
 1005	!.
 e_frel2(?Term1, ?Term2, ?Degree) is nondet
Compares Term1 and Term2 using '~2~' fuzzy relation and returns the approximation Degree of the result (if it's greater than 0).
 1014e_frel2(Term1, Term2, Degree) :-
 1015	flags:get_bpl_flag(lambda_cut(Lambda)),
 1016	compare_terms(frel2, Term1, Term2, Lambda, Degree).
 e_frel2(?Term1, ?Term2, +Comparer, ?Value) is semidet
Compares Term1 and Term2 using '~2~' fuzzy relation and succeeds only if the resulting approximation degree satisfies the expression "degree Comparer Value" (for example, "degree > 0.5"). Comparer can be any Prolog arithmetic comparison operator (=:=, =\=, >=, =<, >, <) or the unification operator (in the latter case, Value will be unified with the approximation degree).
 1029e_frel2(Term1, Term2, Comparer, Value) :-
 1030	e_frel2(Term1, Term2, Degree),
 1031	apply(Comparer, [Degree, Value]),
 1032	!.
 e_frel3(?Term1, ?Term2, ?Degree) is nondet
Compares Term1 and Term2 using '~3~' fuzzy relation and returns the approximation Degree of the result (if it's greater than 0).
 1041e_frel3(Term1, Term2, Degree) :-
 1042	flags:get_bpl_flag(lambda_cut(Lambda)),
 1043	compare_terms(frel3, Term1, Term2, Lambda, Degree).
 e_frel3(?Term1, ?Term2, +Comparer, ?Value) is semidet
Compares Term1 and Term2 using '~3~' fuzzy relation and succeeds only if the resulting approximation degree satisfies the expression "degree Comparer Value" (for example, "degree > 0.5"). Comparer can be any Prolog arithmetic comparison operator (=:=, =\=, >=, =<, >, <) or the unification operator (in the latter case, Value will be unified with the approximation degree).
 1056e_frel3(Term1, Term2, Comparer, Value) :-
 1057	e_frel3(Term1, Term2, Degree),
 1058	apply(Comparer, [Degree, Value]),
 1059	!.
 e_gEqThan(?Term1, ?Term2, ?Degree) is nondet
Compares Term1 and Term2 using '~>' ("less general than" / "greater or equal than") fuzzy relation and returns the approximation Degree of the result (if it's greater than 0).
 1069e_gEqThan(Term1, Term2, Degree) :-
 1070	flags:get_bpl_flag(lambda_cut(Lambda)),
 1071	compare_terms(gEqThan, Term1, Term2, Lambda, Degree).
 e_gEqThan(?Term1, ?Term2, +Comparer, ?Value) is semidet
Compares Term1 and Term2 using '~>' ("less general than" / "greater or equal than") fuzzy relation and succeeds only if the resulting approximation degree satisfies the expression "degree Comparer Value" (for example, "degree > 0.5"). Comparer can be any Prolog arithmetic comparison operator (=:=, =\=, >=, =<, >, <) or the unification operator (in the latter case, Value will be unified with the approximation degree).
 1085e_gEqThan(Term1, Term2, Comparer, Value) :-
 1086	e_gEqThan(Term1, Term2, Degree),
 1087	apply(Comparer, [Degree, Value]),
 1088	!.
 e_lEqThan(?Term1, ?Term2, ?Degree) is nondet
Compares Term1 and Term2 using '<~' ("more general than" / "less or equal than") fuzzy relation and returns the approximation Degree of the result (if it's greater than 0).
 1098e_lEqThan(Term1, Term2, Degree) :-
 1099	flags:get_bpl_flag(lambda_cut(Lambda)),
 1100	compare_terms(lEqThan, Term1, Term2, Lambda, Degree).
 e_lEqThan(?Term1, ?Term2, +Comparer, ?Value) is semidet
Compares Term1 and Term2 using '<~' ("more general than" / "less or equal than") fuzzy relation and succeeds only if the resulting approximation degree satisfies the expression "degree Comparer Value" (for example, "degree > 0.5"). Comparer can be any Prolog arithmetic comparison operator (=:=, =\=, >=, =<, >, <) or the unification operator (in the latter case, Value will be unified with the approximation degree).
 1114e_lEqThan(Term1, Term2, Comparer, Value) :-
 1115	e_lEqThan(Term1, Term2, Degree),
 1116	apply(Comparer, [Degree, Value]),
 1117	!.
 compare_terms(+Relation, ?Term1, ?Term2, +Lambda, ?Degree)
Compares Term1 and Term2 using the specified fuzzy Relation and Lambda-cut value, and returns the approximation Degree in which both terms are similar.
 1127compare_terms(Relation, Term1, Term2, _Lambda, Degree) :-
 1128	% Variable-Variable comparison (two variables are related with
 1129	% approximation degree 1 only if they're exactly the same variables
 1130	% and the fuzzy relation is reflexive)
 1131	var(Term1), var(Term2), !,
 1132	Term1 == Term2,
 1133	apply(Relation, [Term1, Term2, Degree]),
 1134	var(Term1), var(Term2).
 1135
 1136compare_terms(Relation, Term1, Term2, Lambda, Degree) :-
 1137	% Atomic-Atomic comparison
 1138	atomic(Term1), atomic(Term2), !,
 1139	apply(Relation, [Term1, Term2, Degree]),
 1140	Degree >= Lambda.
 1141
 1142compare_terms(Relation, Term1, Term2, Lambda, Degree) :-
 1143	% Compound-Compound comparison
 1144	compound(Term1), compound(Term2), !,
 1145	Term1 =.. [Functor1|Args1],
 1146	Term2 =.. [Functor2|Args2],
 1147	length(Args1, Arity),
 1148	length(Args2, Arity),
 1149	apply(Relation, [Functor1, Functor2, DegreeFunctor]),
 1150	DegreeFunctor >= Lambda,
 1151	compare_args(Args1, Args2, Relation, Lambda, DegreeArgs),
 1152	Degree is min(DegreeFunctor, DegreeArgs).
 compare_args(?Args1, ?Args2, +Relation, +Lambda, ?Degree)
Checks if the terms in the lists Args1 and Args2 are similar one with each other using the given fuzzy Relation, and returns the minimum approximation Degree of the results.
 1162compare_args([], [], _Relation, _Lambda, 1).
 1163
 1164compare_args([Arg1|MoreArgs1], [Arg2|MoreArgs2], Relation, Lambda, Degree) :-
 1165	compare_terms(Relation, Arg1, Arg2, Lambda, DegreeArg),
 1166	compare_args(MoreArgs1, MoreArgs2, Relation, Lambda, DegreeMoreArgs),
 1167	Degree is min(DegreeArg, DegreeMoreArgs). % WARNING: a1, a2, a3
 1168
 1169
 1170
 1171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 1172% Helper predicates used by TPL programs
 1173%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 eval_negation(+NegType, :Goal, +DegreeVars, -Degree)
Executes Goal and returns the approximation Degree of its negation depending on the selected negation type ('not' or '\+'). DegreeVars is the list of degree variables that appears in Goal, which is used to compute the approximation Degree of the result.
 1184eval_negation(not, Goal, DegreeVars, Degree) :-
 1185	% Weak Negation As Failure
 1186%	(bpl_call(Goal), ! ->
 1187	(Goal, ! ->
 1188		degree_composition(DegreeVars, DegreeGoal),
 1189		(DegreeGoal =:= 1 ->
 1190			fail
 1191		;
 1192			Degree is 1 - DegreeGoal
 1193		)
 1194	;
 1195		Degree is 1
 1196	).
 1197
 1198eval_negation(\+, Goal, DegreeVars, Degree) :-
 1199	% Crisp Negation As Failure
 1200% 	(bpl_call(Goal), ! ->
 1201	(Goal, ! ->
 1202		degree_composition(DegreeVars, DegreeGoal),
 1203		(DegreeGoal =:= 1 ->
 1204			fail
 1205		;
 1206			Degree is 1
 1207		)
 1208	;
 1209		Degree is 1
 1210	).
 1211
 1212eval_negation(not, Goal, _BlockConstraints, DegreeVars, Degree) :-
 1213  eval_negation(not, Goal, DegreeVars, Degree).
 1214
 1215eval_negation((\+), Goal, _BlockConstraints, DegreeVars, Degree) :-
 1216  eval_negation((\+), Goal, DegreeVars, Degree).
 over_lambdacut(+Degree) is semidet
Succeeds if the specified approximation Degree is greater than the current lambda-cut value.
 1225over_lambdacut(Degree) :-
 1226	flags:get_bpl_flag(lambda_cut(Lambda)),
 1227	Degree >= Lambda.
 degree_composition(+List, -Degree) is det
Returns the approximation degree for the sim relation as the composition of approximation degrees in List.
 degree_composition_aux(+List, -MinDegree)
Internal predicate used to avoid backtracking.
See also
- degree_composition/2
 1243% degree_composition([], 1.0).
 1244% degree_composition([Number], Number).
 1245% degree_composition([Number1,Number2|List], Degree) :-
 1246%   number(Number1), 
 1247%   !,
 1248%   degree_composition([Number2|List], CurrentDegree),
 1249%   t_norm_current_op(Number1, CurrentDegree, Degree).
 1250% degree_composition([_NotANumber|List], Degree) :-
 1251%   degree_composition(List, Degree).
 1252
 1253degree_composition(List, Degree) :-
 1254	degree_composition_aux(List, Degree), 
 1255	!.
 1256
 1257degree_composition_aux([], 1).
 1258
 1259degree_composition_aux([Number|List], Degree) :-
 1260	number(Number), 
 1261	!,
 1262	degree_composition_aux(List, PartialDegree),
 1263	t_norm_current_op(Number, PartialDegree, Degree).
 1264
 1265degree_composition_aux([_NotANumber|List], Degree) :-
 1266	degree_composition_aux(List, Degree).
 t_norm_current_op(+List, -Degree)
Internal predicate used to avoid backtracking. This predicate is updated whenever the t-norm changes.
See also
- t_norm/2
 1278:- dynamic(t_norm_current_op/3). 1279
 1280t_norm_current_op(D1, D2, D) :-    
 1281  D is min(D1, D2).  
 t_norm_op(+TNorm, +Degree1, +Degree2, -Degree)
t-norm binary operator: Given a t-norm and two degrees, returns the computed result degree
 1289t_norm_op(yes, D1,D2, D) :- % 'yes', 'no', 'min' and 'goedel' use min
 1290  D is min(D1, D2).  
 1291t_norm_op(no, D1, D2, D) :-
 1292  D is min(D1, D2).  
 1293t_norm_op(min, D1, D2, D) :-    
 1294  D is min(D1, D2).  
 1295t_norm_op(product, D1, D2, D) :-
 1296  D is D1*D2.  
 1297%  clpq_solve(D1*D2, D).
 1298t_norm_op(luka, D1, D2, D) :-
 1299  D is max(0, D1+D2-1.0).
 1300%  clpq_solve(D1+D2-1.0, DT),
 1301%  D is max(0, DT).
 1302t_norm_op(drastic, D1, D2, D) :-
 1303  (D1=1.0, D=D2, !) ; (D2=1.0, D=D1).
 1304t_norm_op(nilpotent, D1, D2, D) :-
 1305  (D1+D2>1.0, D is min(D1, D2), !) ; (D1+D2=<1.0, D=0.0).
 1306t_norm_op(hamacher, D1, D2, D) :-
 1307  (D1=0.0, D2=0.0, D=0.0, !) ; (D1+D2>0.0, D is D1*D2/(D1+D2-D1*D2)).
 1308%  (D1=0.0, D2=0.0, D=0.0, !) ; (D1+D2>0.0, clpq_solve(D1*D2/(D1+D2-D1*D2), D)).
 t_norm_op(+Degree1, +Degree2, -Degree)
t-norm binary operator for the default relation: Given a t-norm and two degrees, returns the computed result degree
 1317t_norm_op(Degree1, Degree2, Degree) :-
 1318  t_norm('~',TNorm),
 1319  t_norm_op(TNorm, Degree1, Degree2, Degree).
 bpl_call(:Goal)
Extension of the call/1 predicate for Bousi-Prolog. This predicate just executes specified Goal under this module. However, if Goal is not a call to a Prolog predefined predicate or a predicate currently loaded into this module, it'll be appended a degree variable before executing it.
 1331bpl_call(Goal) :-
 1332	functor(Goal, Functor, Arity),
 1333	current_predicate(Functor/Arity),
 1334	% Just executes the goal
 1335	!,
 1336	Goal.
 1337
 1338% bpl_call(Goal) :-
 1339% 	% Adds a new degree variable to the arguments of the goal
 1340% 	Goal =.. [Functor|Args],
 1341% 	append(Args, [_], NewArgs),
 1342% 	% Appends the prefix of the currently loaded program to the functor
 1343% 	flags:get_bpl_flag(program_prefix(ProgramPrefix)),
 1344% 	concat_atom([ProgramPrefix, '_', Functor], NewFunctor),
 1345% 	% Executes the new goal
 1346% 	apply(NewFunctor, NewArgs).
 1347bpl_call(Goal) :-
 1348  % Build the corresponding query, with prefix, degree and block variables
 1349  parser:build_query(Goal, [Query, _DegreeVars]),
 1350	% Executes the new goal
 1351	Query.
 bpl_apply(:Goal, +List)
Extension of the apply/2 predicate for Bousi-Prolog. This predicate does exactly the same as apply/2, but executes the resulting terms using bpl_call/1 instead of call/1.
 1361bpl_apply(Term, List) :-
 1362	Term =.. [Functor|Args],
 1363	append(Args, List, NewArgs),
 1364	NewTerm =.. [Functor|NewArgs],
 1365	bpl_call(NewTerm).
 bpl_maplist(:Goal, +List)
Extension of the maplist/2 predicate for Bousi-Prolog. This predicate does exactly the same as maplist/2, but executes the resulting terms using bpl_call/1 instead of call/1.
 1375bpl_maplist(_Term, []).
 1376
 1377bpl_maplist(Term, [Item|MoreItems]) :-
 1378	Term =.. [Functor|Args],
 1379	append(Args, [Item], NewArgs),
 1380	NewTerm =.. [Functor|NewArgs],
 1381	bpl_call(NewTerm),
 1382	bpl_maplist(Term, MoreItems).
 1383
 1384
 1385
 1386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 1387% Miscellaneous predicates
 1388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 get_actual_predicate_definition(+InternalPredicate, -ActualPredicate)
Converts a TPL predicate definition into its original BPL predicate definition, which doesn't include the "evaluator" module nor the program prefix and has a smaller arity. If the predicate definition isn't recognised as a TPL predicate, it'll be returned as is.
 1399get_actual_predicate_definition(InternalPredicate, ActualPred/ActualArity) :-
 1400	% Removes the "evaluator" module (if it's present), the program
 1401	% prefix and decreases the arity; for example, if the currently
 1402	% loaded program is "file.bpl", given "evaluator:file_procedure/3",
 1403	% this predicate will return "procedure/2"
 1404	(
 1405		InternalPredicate = evaluator:Pred/Arity
 1406	;
 1407		InternalPredicate = Pred/Arity
 1408	),
 1409	flags:get_bpl_flag(program_prefix(Prefix)),
 1410	atom_length(Prefix, PrefixLength),
 1411	FullPrefixLength is PrefixLength + 1,
 1412	sub_atom(Pred, 0, PrefixLength, _, Prefix),
 1413	sub_atom(Pred, FullPrefixLength, _, 0, ActualPredAux),
 1414	translator:actual_rule_arity(Arity, ActualArityAux),
 1415	(
 1416		% Sometimes, undefined BPL predicates are translated twice; in
 1417		% that cases, here we remove the program prefix and decrease
 1418		% the arity again
 1419		sub_atom(ActualPredAux, 0, PrefixLength, _, Prefix),
 1420		sub_atom(ActualPredAux, FullPrefixLength, _, 0, ActualPred),
 1421		translator:actual_rule_arity(ActualArityAux, ActualArity)
 1422	;
 1423		ActualPred = ActualPredAux,
 1424		ActualArity = ActualArityAux
 1425	),
 1426	!.
 1427
 1428get_actual_predicate_definition(evaluator:Pred/Arity, Pred/Arity) :-
 1429	% Just removes the "evaluator" module from the predicate definition
 1430	!.
 1431
 1432get_actual_predicate_definition(Predicate, Predicate).
 1433	% Returns the input predicate definition
 1434
 1435
 1436
 1437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 1438% Dynamic predicates loaded from TPL files
 1439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Dynamic predicate which stores the proximity or similarity equations defined in the current Bousi-Prolog program.
 1448:- dynamic sim/3.
Dynamic predicate which stores the proximity or similarity equations defined in the current Bousi-Prolog program and labelled with its block.
 1458:- dynamic sim/4.
Dynamic predicate which stores the "more general than" ("less or equal than") equations defined in the current Bousi-Program program.
 1468:- dynamic lEqThan/3.
Dynamic predicate which stores the "less general than" ("greater or equal than") equations defined in the current Bousi-Program program.
 1478:- dynamic gEqThan/3.
Dynamic predicate which stores the '~1~' fuzzy binary equations defined in the current Bousi-Prolog program.
 1487:- dynamic frel1/3.
Dynamic predicate which stores the '~2~' fuzzy binary equations defined in the current Bousi-Prolog program.
 1496:- dynamic frel2/3.
Dynamic predicate which stores the '~3~' fuzzy binary equations defined in the current Bousi-Prolog program.
 1505:- dynamic frel3/3. 1506
 1507
 1508
 1509%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 1510% Other dynamic predicates
 1511%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Dynamic predicate which contains the name of the last TPL file loaded with load_tpl/1.
See also
- load_tpl/1
 1522:- dynamic current_file/1. 1523
 1524current_file('')