3671 lines
		
	
	
		
			107 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			3671 lines
		
	
	
		
			107 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | /*  $Id$ | ||
|  | 
 | ||
|  |     Part of CHR (Constraint Handling Rules) | ||
|  | 
 | ||
|  |     Author:        Tom Schrijvers | ||
|  |     E-mail:        Tom.Schrijvers@cs.kuleuven.be | ||
|  |     WWW:           http://www.swi-prolog.org | ||
|  |     Copyright (C): 2003-2004, K.U. Leuven | ||
|  | 
 | ||
|  |     This program is free software; you can redistribute it and/or | ||
|  |     modify it under the terms of the GNU General Public License | ||
|  |     as published by the Free Software Foundation; either version 2 | ||
|  |     of the License, or (at your option) any later version. | ||
|  | 
 | ||
|  |     This program is distributed in the hope that it will be useful, | ||
|  |     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
|  |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||
|  |     GNU General Public License for more details. | ||
|  | 
 | ||
|  |     You should have received a copy of the GNU Lesser General Public | ||
|  |     License along with this library; if not, write to the Free Software | ||
|  |     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA | ||
|  | 
 | ||
|  |     As a special exception, if you link this library with other files, | ||
|  |     compiled with a Free Software compiler, to produce an executable, this | ||
|  |     library does not by itself cause the resulting executable to be covered | ||
|  |     by the GNU General Public License. This exception does not however | ||
|  |     invalidate any other reasons why the executable file might be covered by | ||
|  |     the GNU General Public License. | ||
|  | */ | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %% | ||
|  | %%   ____ _   _ ____     ____                      _ _ | ||
|  | %%  / ___| | | |  _ \   / ___|___  _ __ ___  _ __ (_) | ___ _ __ | ||
|  | %% | |   | |_| | |_) | | |   / _ \| '_ ` _ \| '_ \| | |/ _ \ '__| | ||
|  | %% | |___|  _  |  _ <  | |__| (_) | | | | | | |_) | | |  __/ | | ||
|  | %%  \____|_| |_|_| \_\  \____\___/|_| |_| |_| .__/|_|_|\___|_| | ||
|  | %%                                          |_| | ||
|  | %% | ||
|  | %% hProlog CHR compiler: | ||
|  | %% | ||
|  | %%	* by Tom Schrijvers, K.U. Leuven, Tom.Schrijvers@cs.kuleuven.be | ||
|  | %% | ||
|  | %%	* based on the SICStus CHR compilation by Christian Holzbaur | ||
|  | %% | ||
|  | %% First working version: 6 June 2003 | ||
|  | %% | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %% | ||
|  | %% URGENTLY TODO | ||
|  | %% | ||
|  | %%	* fine-tune automatic selection of constraint stores | ||
|  | %% | ||
|  | %% To Do | ||
|  | %% | ||
|  | %%	* further specialize runtime predicates for special cases where | ||
|  | %%	  - none of the constraints contain any indexing variables, ... | ||
|  | %%	  - just one constraint requires some runtime predicate | ||
|  | %%	* analysis for attachment delaying (see primes for case) | ||
|  | %%	* internal constraints declaration + analyses? | ||
|  | %%	* Do not store in global variable store if not necessary | ||
|  | %%		NOTE: affects show_store/1 | ||
|  | %%	* multi-level store: variable - ground | ||
|  | %%	* Do not maintain/check unnecessary propagation history | ||
|  | %%		for rules that cannot be applied more than once | ||
|  | %%		e.g. due to groundness | ||
|  | %%	* Strengthen attachment analysis: | ||
|  | %%		reason about bodies of rules only containing constraints | ||
|  | %% | ||
|  | %%	* SICStus compatibility | ||
|  | %%		- rules/1 declaration | ||
|  | %%		- options | ||
|  | %%		- pragmas | ||
|  | %%		- tell guard | ||
|  | %%	* instantiation declarations | ||
|  | %%		POTENTIAL GAIN: | ||
|  | %%			GROUND | ||
|  | %%			- cheaper matching code? | ||
|  | %%			VARIABLE (never bound) | ||
|  | %% | ||
|  | %%	* make difference between cheap guards		for reordering | ||
|  | %%	                      and non-binding guards	for lock removal | ||
|  | %%	* unqiue -> once/[] transformation for propagation | ||
|  | %%	* cheap guards interleaved with head retrieval + faster | ||
|  | %%	  via-retrieval + non-empty checking for propagation rules | ||
|  | %%	  redo for simpagation_head2 prelude | ||
|  | %%	* intelligent backtracking for simplification/simpagation rule | ||
|  | %%		generator_1(X),'_$savecp'(CP_1), | ||
|  | %%              ... | ||
|  | %%              if( ( | ||
|  | %%			generator_n(Y), | ||
|  | %%			test(X,Y) | ||
|  | %%		    ), | ||
|  | %%		    true, | ||
|  | %%		    ('_$cutto'(CP_1), fail) | ||
|  | %%		), | ||
|  | %%		... | ||
|  | %% | ||
|  | %%	  or recently developped cascading-supported approach | ||
|  | %% | ||
|  | %%      * intelligent backtracking for propagation rule | ||
|  | %%          use additional boolean argument for each possible smart backtracking | ||
|  | %%          when boolean at end of list true  -> no smart backtracking | ||
|  | %%                                      false -> smart backtracking | ||
|  | %%          only works for rules with at least 3 constraints in the head | ||
|  | %% | ||
|  | %%	* mutually exclusive rules | ||
|  | %%	* (set semantics + functional dependency) declaration + resolution | ||
|  | %% | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | :- module(chr_translate, | ||
|  | 	  [ chr_translate/2		% +Decls, -TranslatedDecls | ||
|  | 	  ]). | ||
|  | %% SWI begin | ||
|  | :- use_module(library(lists),[append/3,member/2,delete/3,reverse/2,permutation/2]). | ||
|  | :- use_module(library(ordsets)). | ||
|  | %% SWI end | ||
|  | 
 | ||
|  | :- use_module(library(dialect/hprolog)). | ||
|  | :- use_module(pairlist). | ||
|  | :- use_module(a_star). | ||
|  | :- use_module(clean_code). | ||
|  | :- use_module(builtins). | ||
|  | :- use_module(find). | ||
|  | :- include(chr_op2). | ||
|  | 
 | ||
|  | :- chr_option(debug,off). | ||
|  | :- chr_option(optimize,full). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | :- chr_constraint | ||
|  | 
 | ||
|  | 	constraint/2,				% constraint(F/A,ConstraintIndex) | ||
|  | 	get_constraint/2, | ||
|  | 
 | ||
|  | 	constraint_count/1,			% constraint_count(MaxConstraintIndex) | ||
|  | 	get_constraint_count/1, | ||
|  | 
 | ||
|  | 	constraint_index/2,			% constraint_index(F/A,DefaultStoreAndAttachedIndex) | ||
|  | 	get_constraint_index/2, | ||
|  | 
 | ||
|  | 	max_constraint_index/1,			% max_constraint_index(MaxDefaultStoreAndAttachedIndex) | ||
|  | 	get_max_constraint_index/1, | ||
|  | 
 | ||
|  | 	target_module/1,			% target_module(Module) | ||
|  | 	get_target_module/1, | ||
|  | 
 | ||
|  | 	attached/2,				% attached(F/A,yes/no/maybe) | ||
|  | 	is_attached/1, | ||
|  | 
 | ||
|  | 	indexed_argument/2,			% argument instantiation may enable applicability of rule | ||
|  | 	is_indexed_argument/2, | ||
|  | 
 | ||
|  | 	constraint_mode/2, | ||
|  | 	get_constraint_mode/2, | ||
|  | 
 | ||
|  | 	may_trigger/1, | ||
|  | 
 | ||
|  | 	has_nonground_indexed_argument/3, | ||
|  | 
 | ||
|  | 	store_type/2, | ||
|  | 	get_store_type/2, | ||
|  | 	update_store_type/2, | ||
|  | 	actual_store_types/2, | ||
|  | 	assumed_store_type/2, | ||
|  | 	validate_store_type_assumption/1, | ||
|  | 
 | ||
|  | 	rule_count/1, | ||
|  | 	inc_rule_count/1, | ||
|  | 	get_rule_count/1, | ||
|  | 
 | ||
|  | 	passive/2, | ||
|  | 	is_passive/2, | ||
|  | 	any_passive_head/1, | ||
|  | 
 | ||
|  | 	pragma_unique/3, | ||
|  | 	get_pragma_unique/3, | ||
|  | 
 | ||
|  | 	occurrence/4, | ||
|  | 	get_occurrence/4, | ||
|  | 
 | ||
|  | 	max_occurrence/2, | ||
|  | 	get_max_occurrence/2, | ||
|  | 
 | ||
|  | 	allocation_occurrence/2, | ||
|  | 	get_allocation_occurrence/2, | ||
|  | 	rule/2, | ||
|  | 	get_rule/2 | ||
|  | 	. | ||
|  | 
 | ||
|  | :- chr_option(mode,constraint(+,+)). | ||
|  | :- chr_option(mode,constraint_count(+)). | ||
|  | :- chr_option(mode,constraint_index(+,+)). | ||
|  | :- chr_option(mode,max_constraint_index(+)). | ||
|  | :- chr_option(mode,target_module(+)). | ||
|  | :- chr_option(mode,attached(+,+)). | ||
|  | :- chr_option(mode,indexed_argument(+,+)). | ||
|  | :- chr_option(mode,constraint_mode(+,+)). | ||
|  | :- chr_option(mode,may_trigger(+)). | ||
|  | :- chr_option(mode,store_type(+,+)). | ||
|  | :- chr_option(mode,actual_store_types(+,+)). | ||
|  | :- chr_option(mode,assumed_store_type(+,+)). | ||
|  | :- chr_option(mode,rule_count(+)). | ||
|  | :- chr_option(mode,passive(+,+)). | ||
|  | :- chr_option(mode,pragma_unique(+,+,?)). | ||
|  | :- chr_option(mode,occurrence(+,+,+,+)). | ||
|  | :- chr_option(mode,max_occurrence(+,+)). | ||
|  | :- chr_option(mode,allocation_occurrence(+,+)). | ||
|  | :- chr_option(mode,rule(+,+)). | ||
|  | 
 | ||
|  | constraint(FA,Index)  \ get_constraint(Query,Index) | ||
|  | 	<=> Query = FA. | ||
|  | get_constraint(_,_) | ||
|  | 	<=> fail. | ||
|  | 
 | ||
|  | constraint_count(Index) \ get_constraint_count(Query) | ||
|  | 	<=> Query = Index. | ||
|  | get_constraint_count(Query) | ||
|  | 	<=> Query = 0. | ||
|  | 
 | ||
|  | target_module(Mod) \ get_target_module(Query) | ||
|  | 	<=> Query = Mod . | ||
|  | get_target_module(Query) | ||
|  | 	<=> Query = user. | ||
|  | 
 | ||
|  | constraint_index(C,Index) \ get_constraint_index(C,Query) | ||
|  | 	<=> Query = Index. | ||
|  | get_constraint_index(_,_) | ||
|  | 	<=> fail. | ||
|  | 
 | ||
|  | max_constraint_index(Index) \ get_max_constraint_index(Query) | ||
|  | 	<=> Query = Index. | ||
|  | get_max_constraint_index(Query) | ||
|  | 	<=> Query = 0. | ||
|  | 
 | ||
|  | attached(Constr,yes) \ attached(Constr,_) <=> true. | ||
|  | attached(Constr,no) \ attached(Constr,_) <=> true. | ||
|  | attached(Constr,maybe) \ attached(Constr,maybe) <=> true. | ||
|  | 
 | ||
|  | attached(Constr,Type) \ is_attached(Constr) | ||
|  | 	<=> Type \== no. | ||
|  | is_attached(_) <=> true. | ||
|  | 
 | ||
|  | indexed_argument(FA,I) \ indexed_argument(FA,I) <=> true. | ||
|  | indexed_argument(FA,I) \ is_indexed_argument(FA,I) <=> true. | ||
|  | is_indexed_argument(_,_) <=> fail. | ||
|  | 
 | ||
|  | constraint_mode(FA,Mode) \ get_constraint_mode(FA,Query) | ||
|  | 	<=> Query = Mode. | ||
|  | get_constraint_mode(FA,Query) | ||
|  | 	<=> FA = _/A, length(Query,A), set_elems(Query,?). | ||
|  | 
 | ||
|  | may_trigger(FA) <=> | ||
|  |   is_attached(FA), | ||
|  |   get_constraint_mode(FA,Mode), | ||
|  |   has_nonground_indexed_argument(FA,1,Mode). | ||
|  | 
 | ||
|  | has_nonground_indexed_argument(FA,I,[Mode|Modes]) | ||
|  | 	<=> | ||
|  | 		true | ||
|  | 	| | ||
|  | 		( is_indexed_argument(FA,I), | ||
|  | 		  Mode \== (+) -> | ||
|  | 			true | ||
|  | 		; | ||
|  | 			J is I + 1, | ||
|  | 			has_nonground_indexed_argument(FA,J,Modes) | ||
|  | 		). | ||
|  | has_nonground_indexed_argument(_,_,_) | ||
|  | 	<=> fail. | ||
|  | 
 | ||
|  | store_type(FA,atom_hash(Index)) <=> store_type(FA,multi_hash([Index])). | ||
|  | store_type(FA,Store) \ get_store_type(FA,Query) | ||
|  | 	<=> Query = Store. | ||
|  | assumed_store_type(FA,Store) \ get_store_type(FA,Query) | ||
|  | 	<=> Query = Store. | ||
|  | get_store_type(_,Query) | ||
|  | 	<=> Query = default. | ||
|  | 
 | ||
|  | actual_store_types(C,STs) \ update_store_type(C,ST) | ||
|  | 	<=> member(ST,STs) | true. | ||
|  | update_store_type(C,ST), actual_store_types(C,STs) | ||
|  | 	<=> | ||
|  | 		actual_store_types(C,[ST|STs]). | ||
|  | update_store_type(C,ST) | ||
|  | 	<=> | ||
|  | 		actual_store_types(C,[ST]). | ||
|  | 
 | ||
|  | % refine store type assumption | ||
|  | validate_store_type_assumption(C), actual_store_types(C,STs), assumed_store_type(C,_)	% automatic assumption | ||
|  | 	<=> | ||
|  | 		store_type(C,multi_store(STs)). | ||
|  | validate_store_type_assumption(C), actual_store_types(C,STs), store_type(C,_)		% user assumption | ||
|  | 	<=> | ||
|  | 		store_type(C,multi_store(STs)). | ||
|  | validate_store_type_assumption(_) | ||
|  | 	<=> true. | ||
|  | 
 | ||
|  | rule_count(C), inc_rule_count(NC) | ||
|  | 	<=> NC is C + 1, rule_count(NC). | ||
|  | inc_rule_count(NC) | ||
|  | 	<=> NC = 1, rule_count(NC). | ||
|  | 
 | ||
|  | rule_count(C) \ get_rule_count(Q) | ||
|  | 	<=> Q = C. | ||
|  | get_rule_count(Q) | ||
|  | 	<=> Q = 0. | ||
|  | 
 | ||
|  | passive(RuleNb,ID) \ is_passive(RuleNb,ID) | ||
|  | 	<=> true. | ||
|  | is_passive(_,_) | ||
|  | 	<=> fail. | ||
|  | passive(RuleNb,_) \ any_passive_head(RuleNb) | ||
|  | 	<=> true. | ||
|  | any_passive_head(_) | ||
|  | 	<=> fail. | ||
|  | 
 | ||
|  | pragma_unique(RuleNb,ID,Vars) \ get_pragma_unique(RuleNb,ID,Query) | ||
|  | 	<=> Query = Vars. | ||
|  | get_pragma_unique(_,_,_) | ||
|  | 	<=> true. | ||
|  | 
 | ||
|  | occurrence(C,ON,Rule,ID) \ get_occurrence(C,ON,QRule,QID) | ||
|  | 	<=> Rule = QRule, ID = QID. | ||
|  | get_occurrence(_,_,_,_) | ||
|  | 	<=> fail. | ||
|  | 
 | ||
|  | occurrence(C,ON,_,_) ==> max_occurrence(C,ON). | ||
|  | max_occurrence(C,N) \ max_occurrence(C,M) | ||
|  | 	<=> N >= M | true. | ||
|  | max_occurrence(C,MON) \ get_max_occurrence(C,Q) | ||
|  | 	<=> Q = MON. | ||
|  | get_max_occurrence(_,Q) | ||
|  | 	<=> Q = 0. | ||
|  | 
 | ||
|  | 	% need not store constraint that is removed | ||
|  | rule(RuleNb,Rule), occurrence(C,O,RuleNb,ID) \ allocation_occurrence(C,O) | ||
|  | 	<=> Rule = pragma(_,ids(IDs1,_),_,_,_), member(ID,IDs) | ||
|  | 	| NO is O + 1, allocation_occurrence(C,NO). | ||
|  | 	% need not store constraint when body is true | ||
|  | rule(RuleNb,Rule), occurrence(C,O,RuleNb,_) \ allocation_occurrence(C,O) | ||
|  | 	<=> Rule = pragma(rule(_,_,_,true),_,_,_,_) | ||
|  | 	| NO is O + 1, allocation_occurrence(C,NO). | ||
|  | 	% cannot store constraint at passive occurrence | ||
|  | occurrence(C,O,RuleNb,ID), passive(RuleNb,ID) \ allocation_occurrence(C,O) | ||
|  | 	<=> NO is O + 1, allocation_occurrence(C,NO). | ||
|  | allocation_occurrence(C,O) \ get_allocation_occurrence(C,Q) | ||
|  | 	<=> Q = O. | ||
|  | get_allocation_occurrence(_,_) | ||
|  | 	<=> fail. | ||
|  | 
 | ||
|  | rule(RuleNb,Rule) \ get_rule(RuleNb,Q) | ||
|  | 	<=> Q = Rule. | ||
|  | get_rule(_,_) | ||
|  | 	<=> fail. | ||
|  | 
 | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %% | ||
|  | %% Translation | ||
|  | 
 | ||
|  | chr_translate(Declarations,NewDeclarations) :- | ||
|  | 	init_chr_pp_flags, | ||
|  | 	partition_clauses(Declarations,Constraints,Rules,OtherClauses), | ||
|  | 	( Constraints == [] -> | ||
|  | 		insert_declarations(OtherClauses, NewDeclarations) | ||
|  | 	; | ||
|  | 		% start analysis | ||
|  | 		add_rules(Rules), | ||
|  | 		check_rules(Rules,Constraints), | ||
|  | 		add_occurrences(Rules), | ||
|  | 		late_allocation(Constraints), | ||
|  | 		unique_analyse_optimise(Rules,NRules), | ||
|  | 		check_attachments(Constraints), | ||
|  | 		assume_constraint_stores(Constraints), | ||
|  | 		set_constraint_indices(Constraints,1), | ||
|  | 		% end analysis | ||
|  | 		constraints_code(Constraints,NRules,ConstraintClauses), | ||
|  | 		validate_store_type_assumptions(Constraints), | ||
|  | 		store_management_preds(Constraints,StoreClauses),	% depends on actual code used | ||
|  | 		insert_declarations(OtherClauses, Clauses0), | ||
|  | 		chr_module_declaration(CHRModuleDeclaration), | ||
|  | 		append([Clauses0, | ||
|  | 			StoreClauses, | ||
|  | 			ConstraintClauses, | ||
|  | 			CHRModuleDeclaration | ||
|  | 		       ], | ||
|  | 		       NewDeclarations) | ||
|  | 	). | ||
|  | 
 | ||
|  | store_management_preds(Constraints,Clauses) :- | ||
|  | 		generate_attach_detach_a_constraint_all(Constraints,AttachAConstraintClauses), | ||
|  | 		generate_indexed_variables_clauses(Constraints,IndexedClauses), | ||
|  | 		generate_attach_increment(AttachIncrementClauses), | ||
|  | 		generate_attr_unify_hook(AttrUnifyHookClauses), | ||
|  | 		generate_extra_clauses(Constraints,ExtraClauses), | ||
|  | 		generate_insert_delete_constraints(Constraints,DeleteClauses), | ||
|  | 		generate_store_code(Constraints,StoreClauses), | ||
|  | 		append([AttachAConstraintClauses | ||
|  | 		       ,IndexedClauses | ||
|  | 		       ,AttachIncrementClauses | ||
|  | 		       ,AttrUnifyHookClauses | ||
|  | 		       ,ExtraClauses | ||
|  | 		       ,DeleteClauses | ||
|  | 		       ,StoreClauses] | ||
|  | 		      ,Clauses). | ||
|  | 
 | ||
|  | 
 | ||
|  | %% SWI begin | ||
|  | specific_declarations([(:- use_module('chr_runtime')) | ||
|  | 		      ,(:- use_module('chr_hashtable_store')) | ||
|  | 		      ,(:- style_check(-discontiguous)) | ||
|  | 		      |Tail],Tail). | ||
|  | %% SWI end | ||
|  | 
 | ||
|  | %% SICStus begin | ||
|  | %% specific_declarations([(:- use_module('chr_runtime')), | ||
|  | %%		       (:- use_module('chr_hashtable_store')), | ||
|  | %%		       (:- set_prolog_flag(discontiguous_warnings,off)), | ||
|  | %%		       (:- set_prolog_flag(single_var_warnings,off)) | ||
|  | %%		      |Tail],Tail). | ||
|  | %% SICStus end | ||
|  | 
 | ||
|  | 
 | ||
|  | insert_declarations(Clauses0, Clauses) :- | ||
|  | 	specific_declarations(Decls,Tail), | ||
|  | 	( Clauses0 = [ (:- module(M,E))|FileBody] -> | ||
|  | 	    Clauses = [ (:- module(M,E))|Decls], | ||
|  | 	    Tail = FileBody | ||
|  | 	; | ||
|  | 	    Clauses = Decls, | ||
|  | 	    Tail = Clauses0 | ||
|  | 	). | ||
|  | 
 | ||
|  | 
 | ||
|  | chr_module_declaration(CHRModuleDeclaration) :- | ||
|  | 	get_target_module(Mod), | ||
|  | 	( Mod \== chr_translate -> | ||
|  | 		CHRModuleDeclaration = [ | ||
|  | 			(:- multifile chr:'$chr_module'/1), | ||
|  | 			chr:'$chr_module'(Mod) | ||
|  | 		] | ||
|  | 	; | ||
|  | 		CHRModuleDeclaration = [] | ||
|  | 	). | ||
|  | 
 | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %% | ||
|  | %% Partitioning of clauses into constraint declarations, chr rules and other | ||
|  | %% clauses | ||
|  | 
 | ||
|  | partition_clauses([],[],[],[]). | ||
|  | partition_clauses([C|Cs],Ds,Rs,OCs) :- | ||
|  |   (   parse_rule(C,R) -> | ||
|  |       Ds = RDs, | ||
|  |       Rs = [R | RRs], | ||
|  |       OCs = ROCs | ||
|  |   ;   is_declaration(C,D) -> | ||
|  |       append(D,RDs,Ds), | ||
|  |       Rs = RRs, | ||
|  |       OCs = ROCs | ||
|  |   ;   is_module_declaration(C,Mod) -> | ||
|  |       target_module(Mod), | ||
|  |       Ds = RDs, | ||
|  |       Rs = RRs, | ||
|  |       OCs = [C|ROCs] | ||
|  |   ;   C = (handler _) -> | ||
|  |       format('CHR compiler WARNING: ~w.\n',[C]), | ||
|  |       format('    `-->  SICStus compatibility: ignoring handler/1 declaration.\n',[]), | ||
|  |       Ds = RDs, | ||
|  |       Rs = RRs, | ||
|  |       OCs = ROCs | ||
|  |   ;   C = (rules _) -> | ||
|  |       format('CHR compiler WARNING: ~w.\n',[C]), | ||
|  |       format('    `-->  SICStus compatibility: ignoring rules/1 declaration.\n',[]), | ||
|  |       Ds = RDs, | ||
|  |       Rs = RRs, | ||
|  |       OCs = ROCs | ||
|  |   ;   C = (:- chr_option(OptionName,OptionValue)) -> | ||
|  |       handle_option(OptionName,OptionValue), | ||
|  |       Ds = RDs, | ||
|  |       Rs = RRs, | ||
|  |       OCs = ROCs | ||
|  |   ;   C = (:- chr_type _) -> | ||
|  |       Ds = RDs, | ||
|  |       Rs = RRs, | ||
|  |       OCs = ROCs | ||
|  |   ;   Ds = RDs, | ||
|  |       Rs = RRs, | ||
|  |       OCs = [C|ROCs] | ||
|  |   ), | ||
|  |   partition_clauses(Cs,RDs,RRs,ROCs). | ||
|  | 
 | ||
|  | is_declaration(D, Constraints) :-		%% constraint declaration | ||
|  |   D = (:- Decl), | ||
|  |   ( Decl =.. [chr_constraint,Cs] ; Decl =.. [chr_constraint,Cs]), | ||
|  |   conj2list(Cs,Constraints). | ||
|  | 
 | ||
|  | %% Data Declaration | ||
|  | %% | ||
|  | %% pragma_rule | ||
|  | %%	-> pragma( | ||
|  | %%		rule, | ||
|  | %%		ids, | ||
|  | %%		list(pragma), | ||
|  | %%		yesno(string),		:: maybe rule nane | ||
|  | %%		int			:: rule number | ||
|  | %%		) | ||
|  | %% | ||
|  | %% ids	-> ids( | ||
|  | %%		list(int), | ||
|  | %%		list(int) | ||
|  | %%		) | ||
|  | %% | ||
|  | %% rule -> rule( | ||
|  | %%		list(constraint),	:: constraints to be removed | ||
|  | %%		list(constraint),	:: surviving constraints | ||
|  | %%		goal,			:: guard | ||
|  | %%		goal			:: body | ||
|  | %%		) | ||
|  | 
 | ||
|  | parse_rule(RI,R) :-				%% name @ rule | ||
|  | 	RI = (Name @ RI2), !, | ||
|  | 	rule(RI2,yes(Name),R). | ||
|  | parse_rule(RI,R) :- | ||
|  | 	rule(RI,no,R). | ||
|  | 
 | ||
|  | rule(RI,Name,R) :- | ||
|  | 	RI = (RI2 pragma P), !,			%% pragmas | ||
|  | 	is_rule(RI2,R1,IDs), | ||
|  | 	conj2list(P,Ps), | ||
|  | 	inc_rule_count(RuleCount), | ||
|  | 	R = pragma(R1,IDs,Ps,Name,RuleCount). | ||
|  | rule(RI,Name,R) :- | ||
|  | 	is_rule(RI,R1,IDs), | ||
|  | 	inc_rule_count(RuleCount), | ||
|  | 	R = pragma(R1,IDs,[],Name,RuleCount). | ||
|  | 
 | ||
|  | is_rule(RI,R,IDs) :-				%% propagation rule | ||
|  |    RI = (H ==> B), !, | ||
|  |    conj2list(H,Head2i), | ||
|  |    get_ids(Head2i,IDs2,Head2), | ||
|  |    IDs = ids([],IDs2), | ||
|  |    (   B = (G | RB) -> | ||
|  |        R = rule([],Head2,G,RB) | ||
|  |    ; | ||
|  |        R = rule([],Head2,true,B) | ||
|  |    ). | ||
|  | is_rule(RI,R,IDs) :-				%% simplification/simpagation rule | ||
|  |    RI = (H <=> B), !, | ||
|  |    (   B = (G | RB) -> | ||
|  |        Guard = G, | ||
|  |        Body  = RB | ||
|  |    ;   Guard = true, | ||
|  |        Body = B | ||
|  |    ), | ||
|  |    (   H = (H1 \ H2) -> | ||
|  |        conj2list(H1,Head2i), | ||
|  |        conj2list(H2,Head1i), | ||
|  |        get_ids(Head2i,IDs2,Head2,0,N), | ||
|  |        get_ids(Head1i,IDs1,Head1,N,_), | ||
|  |        IDs = ids(IDs1,IDs2) | ||
|  |    ;   conj2list(H,Head1i), | ||
|  |        Head2 = [], | ||
|  |        get_ids(Head1i,IDs1,Head1), | ||
|  |        IDs = ids(IDs1,[]) | ||
|  |    ), | ||
|  |    R = rule(Head1,Head2,Guard,Body). | ||
|  | 
 | ||
|  | get_ids(Cs,IDs,NCs) :- | ||
|  | 	get_ids(Cs,IDs,NCs,0,_). | ||
|  | 
 | ||
|  | get_ids([],[],[],N,N). | ||
|  | get_ids([C|Cs],[N|IDs],[NC|NCs],N,NN) :- | ||
|  | 	( C = (NC # N) -> | ||
|  | 		true | ||
|  | 	; | ||
|  | 		NC = C | ||
|  | 	), | ||
|  | 	M is N + 1, | ||
|  | 	get_ids(Cs,IDs,NCs, M,NN). | ||
|  | 
 | ||
|  | is_module_declaration((:- module(Mod)),Mod). | ||
|  | is_module_declaration((:- module(Mod,_)),Mod). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | % Add rules | ||
|  | add_rules([]). | ||
|  | add_rules([Rule|Rules]) :- | ||
|  | 	Rule = pragma(_,_,_,_,RuleNb), | ||
|  | 	rule(RuleNb,Rule), | ||
|  | 	add_rules(Rules). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %% Some input verification: | ||
|  | %%  - all constraints in heads are declared constraints | ||
|  | %%  - all passive pragmas refer to actual head constraints | ||
|  | 
 | ||
|  | check_rules([],_). | ||
|  | check_rules([PragmaRule|Rest],Decls) :- | ||
|  | 	check_rule(PragmaRule,Decls), | ||
|  | 	check_rules(Rest,Decls). | ||
|  | 
 | ||
|  | check_rule(PragmaRule,Decls) :- | ||
|  | 	check_rule_indexing(PragmaRule), | ||
|  | 	PragmaRule = pragma(Rule,_IDs,Pragmas,_Name,_N), | ||
|  | 	Rule = rule(H1,H2,_,_), | ||
|  | 	append(H1,H2,HeadConstraints), | ||
|  | 	check_head_constraints(HeadConstraints,Decls,PragmaRule), | ||
|  | 	check_pragmas(Pragmas,PragmaRule). | ||
|  | 
 | ||
|  | check_head_constraints([],_,_). | ||
|  | check_head_constraints([Constr|Rest],Decls,PragmaRule) :- | ||
|  | 	functor(Constr,F,A), | ||
|  | 	( member(F/A,Decls) -> | ||
|  | 		check_head_constraints(Rest,Decls,PragmaRule) | ||
|  | 	; | ||
|  | 		format('CHR compiler ERROR: Undeclared constraint ~w in head of ~@.\n', | ||
|  | 		       [F/A,format_rule(PragmaRule)]), | ||
|  | 		format('    `--> Constraint should be one of ~w.\n',[Decls]), | ||
|  | 		fail | ||
|  | 	). | ||
|  | 
 | ||
|  | check_pragmas([],_). | ||
|  | check_pragmas([Pragma|Pragmas],PragmaRule) :- | ||
|  | 	check_pragma(Pragma,PragmaRule), | ||
|  | 	check_pragmas(Pragmas,PragmaRule). | ||
|  | 
 | ||
|  | check_pragma(Pragma,PragmaRule) :- | ||
|  | 	var(Pragma), !, | ||
|  | 	format('CHR compiler ERROR: invalid pragma ~w in ~@.\n', | ||
|  |                [Pragma,format_rule(PragmaRule)]), | ||
|  | 	format('    `--> Pragma should not be a variable!\n',[]), | ||
|  | 	fail. | ||
|  | check_pragma(passive(ID), PragmaRule) :- | ||
|  | 	!, | ||
|  | 	PragmaRule = pragma(_,ids(IDs1,IDs2),_,_,RuleNb), | ||
|  | 	( memberchk_eq(ID,IDs1) -> | ||
|  | 		true | ||
|  | 	; memberchk_eq(ID,IDs2) -> | ||
|  | 		true | ||
|  | 	; | ||
|  | 		format('CHR compiler ERROR: invalid identifier ~w in pragma passive in ~@.\n', | ||
|  |                        [ID,format_rule(PragmaRule)]), | ||
|  | 		fail | ||
|  | 	), | ||
|  | 	passive(RuleNb,ID). | ||
|  | 
 | ||
|  | check_pragma(Pragma, PragmaRule) :- | ||
|  | 	Pragma = unique(ID,Vars), | ||
|  | 	!, | ||
|  | 	PragmaRule = pragma(_,_,_,_,RuleNb), | ||
|  | 	pragma_unique(RuleNb,ID,Vars), | ||
|  | 	format('CHR compiler WARNING: undocumented pragma ~w in ~@.\n',[Pragma,format_rule(PragmaRule)]), | ||
|  | 	format('    `--> Only use this pragma if you know what you are doing.\n',[]). | ||
|  | 
 | ||
|  | check_pragma(Pragma, PragmaRule) :- | ||
|  | 	Pragma = already_in_heads, | ||
|  | 	!, | ||
|  | 	format('CHR compiler WARNING: currently unsupported pragma ~w in ~@.\n',[Pragma,format_rule(PragmaRule)]), | ||
|  | 	format('    `--> Pragma is ignored. Termination and correctness may be affected \n',[]). | ||
|  | 
 | ||
|  | check_pragma(Pragma, PragmaRule) :- | ||
|  | 	Pragma = already_in_head(_), | ||
|  | 	!, | ||
|  | 	format('CHR compiler WARNING: currently unsupported pragma ~w in ~@.\n',[Pragma,format_rule(PragmaRule)]), | ||
|  | 	format('    `--> Pragma is ignored. Termination and correctness may be affected \n',[]). | ||
|  | 
 | ||
|  | check_pragma(Pragma,PragmaRule) :- | ||
|  | 	format('CHR compiler ERROR: invalid pragma ~w in ~@.\n',[Pragma,format_rule(PragmaRule)]), | ||
|  | 	format('    `--> Pragma should be one of passive/1!\n',[]), | ||
|  | 	fail. | ||
|  | 
 | ||
|  | format_rule(PragmaRule) :- | ||
|  | 	PragmaRule = pragma(_,_,_,MaybeName,N), | ||
|  | 	( MaybeName = yes(Name) -> | ||
|  | 		write('rule '), write(Name) | ||
|  | 	; | ||
|  | 		write('rule number '), write(N) | ||
|  | 	). | ||
|  | 
 | ||
|  | check_rule_indexing(PragmaRule) :- | ||
|  | 	PragmaRule = pragma(Rule,_,_,_,_), | ||
|  | 	Rule = rule(H1,H2,G,_), | ||
|  | 	term_variables(H1-H2,HeadVars), | ||
|  | 	remove_anti_monotonic_guards(G,HeadVars,NG), | ||
|  | 	check_indexing(H1,NG-H2), | ||
|  | 	check_indexing(H2,NG-H1). | ||
|  | 
 | ||
|  | remove_anti_monotonic_guards(G,Vars,NG) :- | ||
|  | 	conj2list(G,GL), | ||
|  | 	remove_anti_monotonic_guard_list(GL,Vars,NGL), | ||
|  | 	list2conj(NGL,NG). | ||
|  | 
 | ||
|  | remove_anti_monotonic_guard_list([],_,[]). | ||
|  | remove_anti_monotonic_guard_list([G|Gs],Vars,NGs) :- | ||
|  | 	( G = var(X), | ||
|  |           memberchk_eq(X,Vars) -> | ||
|  | 		NGs = RGs | ||
|  | 	; | ||
|  | 		NGs = [G|RGs] | ||
|  | 	), | ||
|  | 	remove_anti_monotonic_guard_list(Gs,Vars,RGs). | ||
|  | 
 | ||
|  | check_indexing([],_). | ||
|  | check_indexing([Head|Heads],Other) :- | ||
|  | 	functor(Head,F,A), | ||
|  | 	Head =.. [_|Args], | ||
|  | 	term_variables(Heads-Other,OtherVars), | ||
|  | 	check_indexing(Args,1,F/A,OtherVars), | ||
|  | 	check_indexing(Heads,[Head|Other]). | ||
|  | 
 | ||
|  | check_indexing([],_,_,_). | ||
|  | check_indexing([Arg|Args],I,FA,OtherVars) :- | ||
|  | 	( is_indexed_argument(FA,I) -> | ||
|  | 		true | ||
|  | 	; nonvar(Arg) -> | ||
|  | 		indexed_argument(FA,I) | ||
|  | 	; % var(Arg) -> | ||
|  | 		term_variables(Args,ArgsVars), | ||
|  | 		append(ArgsVars,OtherVars,RestVars), | ||
|  | 		( memberchk_eq(Arg,RestVars) -> | ||
|  | 			indexed_argument(FA,I) | ||
|  | 		; | ||
|  | 			true | ||
|  | 		) | ||
|  | 	), | ||
|  | 	J is I + 1, | ||
|  | 	term_variables(Arg,NVars), | ||
|  | 	append(NVars,OtherVars,NOtherVars), | ||
|  | 	check_indexing(Args,J,FA,NOtherVars). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | % Occurrences | ||
|  | 
 | ||
|  | add_occurrences([]). | ||
|  | add_occurrences([Rule|Rules]) :- | ||
|  | 	Rule = pragma(rule(H1,H2,_,_),ids(IDs1,IDs2),_,_,Nb), | ||
|  | 	add_occurrences(H1,IDs1,Nb), | ||
|  | 	add_occurrences(H2,IDs2,Nb), | ||
|  | 	add_occurrences(Rules). | ||
|  | 
 | ||
|  | add_occurrences([],[],_). | ||
|  | add_occurrences([H|Hs],[ID|IDs],RuleNb) :- | ||
|  | 	functor(H,F,A), | ||
|  | 	FA = F/A, | ||
|  | 	get_max_occurrence(FA,MO), | ||
|  | 	O is MO + 1, | ||
|  | 	occurrence(FA,O,RuleNb,ID), | ||
|  | 	add_occurrences(Hs,IDs,RuleNb). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | % Late allocation | ||
|  | 
 | ||
|  | late_allocation([]). | ||
|  | late_allocation([C|Cs]) :- | ||
|  | 	allocation_occurrence(C,1), | ||
|  | 	late_allocation(Cs). | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | % Global Options | ||
|  | % | ||
|  | 
 | ||
|  | handle_option(Var,Value) :- | ||
|  | 	var(Var), !, | ||
|  | 	format('CHR compiler ERROR: ~w.\n',[option(Var,Value)]), | ||
|  | 	format('    `--> First argument should be an atom, not a variable.\n',[]), | ||
|  | 	fail. | ||
|  | 
 | ||
|  | handle_option(Name,Value) :- | ||
|  | 	var(Value), !, | ||
|  | 	format('CHR compiler ERROR: ~w.\n',[option(Name,Value)]), | ||
|  | 	format('    `--> Second argument should be a nonvariable.\n',[]), | ||
|  | 	fail. | ||
|  | 
 | ||
|  | handle_option(Name,Value) :- | ||
|  | 	option_definition(Name,Value,Flags), | ||
|  | 	!, | ||
|  | 	set_chr_pp_flags(Flags). | ||
|  | 
 | ||
|  | handle_option(Name,Value) :- | ||
|  | 	\+ option_definition(Name,_,_), !, | ||
|  | %	setof(N,_V ^ _F ^ (option_definition(N,_V,_F)),Ns), | ||
|  | 	format('CHR compiler WARNING: ~w.\n',[option(Name,Value)]), | ||
|  | 	format('    `--> Invalid option name \n',[]). %~w: should be one of ~w.\n',[Name,Ns]). | ||
|  | 
 | ||
|  | handle_option(Name,Value) :- | ||
|  | 	findall(V,option_definition(Name,V,_),Vs), | ||
|  | 	format('CHR compiler ERROR: ~w.\n',[option(Name,Value)]), | ||
|  | 	format('    `--> Invalid value ~w: should be one of ~w.\n',[Value,Vs]), | ||
|  | 	fail. | ||
|  | 
 | ||
|  | option_definition(optimize,experimental,Flags) :- | ||
|  | 	Flags = [ unique_analyse_optimise  - on, | ||
|  |                   check_unnecessary_active - full, | ||
|  | 		  reorder_heads		   - on, | ||
|  | 		  set_semantics_rule	   - on, | ||
|  | 		  check_attachments	   - on, | ||
|  | 		  guard_via_reschedule     - on | ||
|  | 		]. | ||
|  | option_definition(optimize,full,Flags) :- | ||
|  | 	Flags = [ unique_analyse_optimise  - off, | ||
|  |                   check_unnecessary_active - full, | ||
|  | 		  reorder_heads		   - on, | ||
|  | 		  set_semantics_rule	   - on, | ||
|  | 		  check_attachments	   - on, | ||
|  | 		  guard_via_reschedule     - on | ||
|  | 		]. | ||
|  | 
 | ||
|  | option_definition(optimize,sicstus,Flags) :- | ||
|  | 	Flags = [ unique_analyse_optimise  - off, | ||
|  |                   check_unnecessary_active - simplification, | ||
|  | 		  reorder_heads		   - off, | ||
|  | 		  set_semantics_rule	   - off, | ||
|  | 		  check_attachments	   - off, | ||
|  | 		  guard_via_reschedule     - off | ||
|  | 		]. | ||
|  | 
 | ||
|  | option_definition(optimize,off,Flags) :- | ||
|  | 	Flags = [ unique_analyse_optimise  - off, | ||
|  |                   check_unnecessary_active - off, | ||
|  | 		  reorder_heads		   - off, | ||
|  | 		  set_semantics_rule	   - off, | ||
|  | 		  check_attachments	   - off, | ||
|  | 		  guard_via_reschedule     - off | ||
|  | 		]. | ||
|  | 
 | ||
|  | option_definition(check_guard_bindings,on,Flags) :- | ||
|  | 	Flags = [ guard_locks - on ]. | ||
|  | 
 | ||
|  | option_definition(check_guard_bindings,off,Flags) :- | ||
|  | 	Flags = [ guard_locks - off ]. | ||
|  | 
 | ||
|  | option_definition(reduced_indexing,on,Flags) :- | ||
|  | 	Flags = [ reduced_indexing - on ]. | ||
|  | 
 | ||
|  | option_definition(reduced_indexing,off,Flags) :- | ||
|  | 	Flags = [ reduced_indexing - off ]. | ||
|  | 
 | ||
|  | option_definition(mode,ModeDecl,[]) :- | ||
|  | 	(nonvar(ModeDecl) -> | ||
|  | 	    functor(ModeDecl,F,A), | ||
|  | 	    ModeDecl =.. [_|ArgModes], | ||
|  | 	    constraint_mode(F/A,ArgModes) | ||
|  | 	; | ||
|  | 	    true | ||
|  | 	). | ||
|  | option_definition(store,FA-Store,[]) :- | ||
|  | 	store_type(FA,Store). | ||
|  | 
 | ||
|  | option_definition(debug,on,Flags) :- | ||
|  | 	Flags = [ debugable - on ]. | ||
|  | option_definition(debug,off,Flags) :- | ||
|  | 	Flags = [ debugable - off ]. | ||
|  | option_definition(type_definition, _, []). % JW: ignored by bootstrap compiler | ||
|  | option_definition(type_declaration, _, []). % JW: ignored by bootstrap compiler | ||
|  | option_definition(verbosity,_,[]). | ||
|  | 
 | ||
|  | init_chr_pp_flags :- | ||
|  | 	chr_pp_flag_definition(Name,[DefaultValue|_]), | ||
|  | 	set_chr_pp_flag(Name,DefaultValue), | ||
|  | 	fail. | ||
|  | init_chr_pp_flags. | ||
|  | 
 | ||
|  | set_chr_pp_flags([]). | ||
|  | set_chr_pp_flags([Name-Value|Flags]) :- | ||
|  | 	set_chr_pp_flag(Name,Value), | ||
|  | 	set_chr_pp_flags(Flags). | ||
|  | 
 | ||
|  | set_chr_pp_flag(Name,Value) :- | ||
|  | 	atom_concat('$chr_pp_',Name,GlobalVar), | ||
|  | 	nb_setval(GlobalVar,Value). | ||
|  | 
 | ||
|  | chr_pp_flag_definition(unique_analyse_optimise,[on,off]). | ||
|  | chr_pp_flag_definition(check_unnecessary_active,[full,simplification,off]). | ||
|  | chr_pp_flag_definition(reorder_heads,[on,off]). | ||
|  | chr_pp_flag_definition(set_semantics_rule,[on,off]). | ||
|  | chr_pp_flag_definition(guard_via_reschedule,[on,off]). | ||
|  | chr_pp_flag_definition(guard_locks,[on,off]). | ||
|  | chr_pp_flag_definition(check_attachments,[on,off]). | ||
|  | chr_pp_flag_definition(debugable,[off,on]). | ||
|  | chr_pp_flag_definition(reduced_indexing,[on,off]). | ||
|  | 
 | ||
|  | chr_pp_flag(Name,Value) :- | ||
|  | 	atom_concat('$chr_pp_',Name,GlobalVar), | ||
|  | 	nb_getval(GlobalVar,V), | ||
|  | 	( V == [] -> | ||
|  | 		chr_pp_flag_definition(Name,[Value|_]) | ||
|  | 	; | ||
|  | 		V = Value | ||
|  | 	). | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %% | ||
|  | %% Generated predicates | ||
|  | %%	attach_$CONSTRAINT | ||
|  | %%	attach_increment | ||
|  | %%	detach_$CONSTRAINT | ||
|  | %%	attr_unify_hook | ||
|  | 
 | ||
|  | %%	attach_$CONSTRAINT | ||
|  | generate_attach_detach_a_constraint_all([],[]). | ||
|  | generate_attach_detach_a_constraint_all([Constraint|Constraints],Clauses) :- | ||
|  | 	( may_trigger(Constraint) -> | ||
|  | 		generate_attach_a_constraint(Constraint,Clauses1), | ||
|  | 		generate_detach_a_constraint(Constraint,Clauses2) | ||
|  | 	; | ||
|  | 		Clauses1 = [], | ||
|  | 		Clauses2 = [] | ||
|  | 	), | ||
|  | 	generate_attach_detach_a_constraint_all(Constraints,Clauses3), | ||
|  | 	append([Clauses1,Clauses2,Clauses3],Clauses). | ||
|  | 
 | ||
|  | generate_attach_a_constraint(Constraint,[Clause1,Clause2]) :- | ||
|  | 	generate_attach_a_constraint_empty_list(Constraint,Clause1), | ||
|  | 	get_max_constraint_index(N), | ||
|  | 	( N == 1 -> | ||
|  | 		generate_attach_a_constraint_1_1(Constraint,Clause2) | ||
|  | 	; | ||
|  | 		generate_attach_a_constraint_t_p(Constraint,Clause2) | ||
|  | 	). | ||
|  | 
 | ||
|  | generate_attach_a_constraint_skeleton(FA,Args,Body,Clause) :- | ||
|  | 	make_name('attach_',FA,Fct), | ||
|  | 	Head =.. [Fct | Args], | ||
|  | 	Clause = ( Head :- Body). | ||
|  | 
 | ||
|  | generate_attach_a_constraint_empty_list(FA,Clause) :- | ||
|  | 	generate_attach_a_constraint_skeleton(FA,[[],_],true,Clause). | ||
|  | 
 | ||
|  | generate_attach_a_constraint_1_1(FA,Clause) :- | ||
|  | 	Args = [[Var|Vars],Susp], | ||
|  | 	generate_attach_a_constraint_skeleton(FA,Args,Body,Clause), | ||
|  | 	generate_attach_body_1(FA,Var,Susp,AttachBody), | ||
|  | 	make_name('attach_',FA,Fct), | ||
|  | 	RecursiveCall =.. [Fct,Vars,Susp], | ||
|  | 	Body = | ||
|  | 	( | ||
|  | 		AttachBody, | ||
|  | 		RecursiveCall | ||
|  | 	). | ||
|  | 
 | ||
|  | generate_attach_body_1(FA,Var,Susp,Body) :- | ||
|  | 	get_target_module(Mod), | ||
|  | 	Body = | ||
|  | 	(   get_attr(Var, Mod, Susps) -> | ||
|  |             NewSusps=[Susp|Susps], | ||
|  |             put_attr(Var, Mod, NewSusps) | ||
|  |         ; | ||
|  |             put_attr(Var, Mod, [Susp]) | ||
|  | 	). | ||
|  | 
 | ||
|  | generate_attach_a_constraint_t_p(FA,Clause) :- | ||
|  | 	Args = [[Var|Vars],Susp], | ||
|  | 	generate_attach_a_constraint_skeleton(FA,Args,Body,Clause), | ||
|  | 	make_name('attach_',FA,Fct), | ||
|  | 	RecursiveCall =.. [Fct,Vars,Susp], | ||
|  | 	generate_attach_body_n(FA,Var,Susp,AttachBody), | ||
|  | 	Body = | ||
|  | 	( | ||
|  | 		AttachBody, | ||
|  | 		RecursiveCall | ||
|  | 	). | ||
|  | 
 | ||
|  | generate_attach_body_n(F/A,Var,Susp,Body) :- | ||
|  | 	get_constraint_index(F/A,Position), | ||
|  | 	or_pattern(Position,Pattern), | ||
|  | 	get_max_constraint_index(Total), | ||
|  | 	make_attr(Total,Mask,SuspsList,Attr), | ||
|  | 	nth1(Position,SuspsList,Susps), | ||
|  | 	substitute_eq(Susps,SuspsList,[Susp|Susps],SuspsList1), | ||
|  | 	make_attr(Total,Mask,SuspsList1,NewAttr1), | ||
|  | 	substitute_eq(Susps,SuspsList,[Susp],SuspsList2), | ||
|  | 	make_attr(Total,NewMask,SuspsList2,NewAttr2), | ||
|  | 	copy_term_nat(SuspsList,SuspsList3), | ||
|  | 	nth1(Position,SuspsList3,[Susp],RestSuspsList), | ||
|  | 	set_elems(RestSuspsList,[]), | ||
|  | 	make_attr(Total,Pattern,SuspsList3,NewAttr3), | ||
|  | 	get_target_module(Mod), | ||
|  | 	Body = | ||
|  | 	( get_attr(Var,Mod,TAttr) -> | ||
|  | 		TAttr = Attr, | ||
|  | 		( Mask /\ Pattern =:= Pattern -> | ||
|  | 			put_attr(Var, Mod, NewAttr1) | ||
|  | 		; | ||
|  | 			NewMask is Mask \/ Pattern, | ||
|  | 			put_attr(Var, Mod, NewAttr2) | ||
|  | 		) | ||
|  | 	; | ||
|  | 		put_attr(Var,Mod,NewAttr3) | ||
|  | 	). | ||
|  | 
 | ||
|  | %%	detach_$CONSTRAINT | ||
|  | generate_detach_a_constraint(Constraint,[Clause1,Clause2]) :- | ||
|  | 	generate_detach_a_constraint_empty_list(Constraint,Clause1), | ||
|  | 	get_max_constraint_index(N), | ||
|  | 	( N == 1 -> | ||
|  | 		generate_detach_a_constraint_1_1(Constraint,Clause2) | ||
|  | 	; | ||
|  | 		generate_detach_a_constraint_t_p(Constraint,Clause2) | ||
|  | 	). | ||
|  | 
 | ||
|  | generate_detach_a_constraint_empty_list(FA,Clause) :- | ||
|  | 	make_name('detach_',FA,Fct), | ||
|  | 	Args = [[],_], | ||
|  | 	Head =.. [Fct | Args], | ||
|  | 	Clause = ( Head :- true). | ||
|  | 
 | ||
|  | generate_detach_a_constraint_1_1(FA,Clause) :- | ||
|  | 	make_name('detach_',FA,Fct), | ||
|  | 	Args = [[Var|Vars],Susp], | ||
|  | 	Head =.. [Fct | Args], | ||
|  | 	RecursiveCall =.. [Fct,Vars,Susp], | ||
|  | 	generate_detach_body_1(FA,Var,Susp,DetachBody), | ||
|  | 	Body = | ||
|  | 	( | ||
|  | 		DetachBody, | ||
|  | 		RecursiveCall | ||
|  | 	), | ||
|  | 	Clause = (Head :- Body). | ||
|  | 
 | ||
|  | generate_detach_body_1(FA,Var,Susp,Body) :- | ||
|  | 	get_target_module(Mod), | ||
|  | 	Body = | ||
|  | 	( get_attr(Var,Mod,Susps) -> | ||
|  | 		'chr sbag_del_element'(Susps,Susp,NewSusps), | ||
|  | 		( NewSusps == [] -> | ||
|  | 			del_attr(Var,Mod) | ||
|  | 		; | ||
|  | 			put_attr(Var,Mod,NewSusps) | ||
|  | 		) | ||
|  | 	; | ||
|  | 		true | ||
|  | 	). | ||
|  | 
 | ||
|  | generate_detach_a_constraint_t_p(FA,Clause) :- | ||
|  | 	make_name('detach_',FA,Fct), | ||
|  | 	Args = [[Var|Vars],Susp], | ||
|  | 	Head =.. [Fct | Args], | ||
|  | 	RecursiveCall =.. [Fct,Vars,Susp], | ||
|  | 	generate_detach_body_n(FA,Var,Susp,DetachBody), | ||
|  | 	Body = | ||
|  | 	( | ||
|  | 		DetachBody, | ||
|  | 		RecursiveCall | ||
|  | 	), | ||
|  | 	Clause = (Head :- Body). | ||
|  | 
 | ||
|  | generate_detach_body_n(F/A,Var,Susp,Body) :- | ||
|  | 	get_constraint_index(F/A,Position), | ||
|  | 	or_pattern(Position,Pattern), | ||
|  | 	and_pattern(Position,DelPattern), | ||
|  | 	get_max_constraint_index(Total), | ||
|  | 	make_attr(Total,Mask,SuspsList,Attr), | ||
|  | 	nth1(Position,SuspsList,Susps), | ||
|  | 	substitute_eq(Susps,SuspsList,[],SuspsList1), | ||
|  | 	make_attr(Total,NewMask,SuspsList1,Attr1), | ||
|  | 	substitute_eq(Susps,SuspsList,NewSusps,SuspsList2), | ||
|  | 	make_attr(Total,Mask,SuspsList2,Attr2), | ||
|  | 	get_target_module(Mod), | ||
|  | 	Body = | ||
|  | 	( get_attr(Var,Mod,TAttr) -> | ||
|  | 		TAttr = Attr, | ||
|  | 		( Mask /\ Pattern =:= Pattern -> | ||
|  | 			'chr sbag_del_element'(Susps,Susp,NewSusps), | ||
|  | 			( NewSusps == [] -> | ||
|  | 				NewMask is Mask /\ DelPattern, | ||
|  | 				( NewMask == 0 -> | ||
|  | 					del_attr(Var,Mod) | ||
|  | 				; | ||
|  | 					put_attr(Var,Mod,Attr1) | ||
|  | 				) | ||
|  | 			; | ||
|  | 				put_attr(Var,Mod,Attr2) | ||
|  | 			) | ||
|  | 		; | ||
|  | 			true | ||
|  | 		) | ||
|  | 	; | ||
|  | 		true | ||
|  | 	). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | generate_indexed_variables_clauses(Constraints,Clauses) :- | ||
|  | 	( forsome(C,Constraints,chr_translate:may_trigger(C)) -> | ||
|  | 		generate_indexed_variables_clauses_(Constraints,Clauses) | ||
|  | 	; | ||
|  | 		Clauses = [] | ||
|  | 	). | ||
|  | 
 | ||
|  | generate_indexed_variables_clauses_([],[]). | ||
|  | generate_indexed_variables_clauses_([C|Cs],Clauses) :- | ||
|  | 	( ( is_attached(C) ; chr_pp_flag(debugable,on)) -> | ||
|  | 		Clauses = [Clause|RestClauses], | ||
|  | 		generate_indexed_variables_clause(C,Clause) | ||
|  | 	; | ||
|  | 		Clauses = RestClauses | ||
|  | 	), | ||
|  | 	generate_indexed_variables_clauses_(Cs,RestClauses). | ||
|  | 
 | ||
|  | generate_indexed_variables_clause(F/A,Clause) :- | ||
|  | 	functor(Term,F,A), | ||
|  | 	get_constraint_mode(F/A,ArgModes), | ||
|  | 	Term =.. [_|Args], | ||
|  | 	create_indexed_variables_body(Args,ArgModes,Vars,1,F/A,MaybeBody,N), | ||
|  | 	( MaybeBody == empty -> | ||
|  | 
 | ||
|  | 		Body = (Vars = []) | ||
|  | 	; N == 0 -> | ||
|  | 		Body = term_variables(Susp,Vars) | ||
|  | 	; | ||
|  | 		MaybeBody = Body | ||
|  | 	), | ||
|  | 	Clause = | ||
|  | 		( '$indexed_variables'(Susp,Vars) :- | ||
|  | 			Susp = Term, | ||
|  | 			Body | ||
|  | 		). | ||
|  | 
 | ||
|  | create_indexed_variables_body([],[],_,_,_,empty,0). | ||
|  | create_indexed_variables_body([V|Vs],[Mode|Modes],Vars,I,FA,Body,N) :- | ||
|  | 	J is I + 1, | ||
|  | 	create_indexed_variables_body(Vs,Modes,Tail,J,FA,RBody,M), | ||
|  | 	( Mode \== (+), | ||
|  |           is_indexed_argument(FA,I) -> | ||
|  | 		( RBody == empty -> | ||
|  | 			Body = term_variables(V,Vars) | ||
|  | 		; | ||
|  | 			Body = (term_variables(V,Vars,Tail),RBody) | ||
|  | 		), | ||
|  | 		N = M | ||
|  | 	; | ||
|  | 		Vars = Tail, | ||
|  | 		Body = RBody, | ||
|  | 		N is M + 1 | ||
|  | 	). | ||
|  | 
 | ||
|  | generate_extra_clauses(Constraints,[A,B,C,D,E]) :- | ||
|  | 	( chr_pp_flag(reduced_indexing,on) -> | ||
|  | 		global_indexed_variables_clause(Constraints,D) | ||
|  | 	; | ||
|  | 		D = | ||
|  | 		( chr_indexed_variables(Susp,Vars) :- | ||
|  | 			'chr chr_indexed_variables'(Susp,Vars) | ||
|  | 		) | ||
|  | 	), | ||
|  | 	generate_remove_clause(A), | ||
|  | 	generate_activate_clause(B), | ||
|  | 	generate_allocate_clause(C), | ||
|  | 	generate_insert_constraint_internal(E). | ||
|  | 
 | ||
|  | generate_remove_clause(RemoveClause) :- | ||
|  | 	RemoveClause = | ||
|  | 	( | ||
|  | 		remove_constraint_internal(Susp, Agenda, Delete) :- | ||
|  | 			arg( 2, Susp, Mref), | ||
|  | 			'chr get_mutable'( State, Mref), | ||
|  | 			'chr update_mutable'( removed, Mref),		% mark in any case | ||
|  | 			( compound(State) ->			% passive/1 | ||
|  | 			    Agenda = [], | ||
|  | 			    Delete = no | ||
|  | 			; State==removed -> | ||
|  | 			    Agenda = [], | ||
|  | 			    Delete = no | ||
|  | 			%; State==triggered -> | ||
|  | 			%     Agenda = [] | ||
|  | 			; | ||
|  | 			    Delete = yes, | ||
|  | 			    chr_indexed_variables(Susp,Agenda) | ||
|  | 			) | ||
|  | 	). | ||
|  | 
 | ||
|  | generate_activate_clause(ActivateClause) :- | ||
|  | 	ActivateClause = | ||
|  | 	( | ||
|  | 		activate_constraint(Store, Vars, Susp, Generation) :- | ||
|  | 			arg( 2, Susp, Mref), | ||
|  | 			'chr get_mutable'( State, Mref), | ||
|  | 			'chr update_mutable'( active, Mref), | ||
|  | 			( nonvar(Generation) ->			% aih | ||
|  | 			    true | ||
|  | 			; | ||
|  | 			    arg( 4, Susp, Gref), | ||
|  | 			    'chr get_mutable'( Gen, Gref), | ||
|  | 			    Generation is Gen+1, | ||
|  | 			    'chr update_mutable'( Generation, Gref) | ||
|  | 			), | ||
|  | 			( compound(State) ->			% passive/1 | ||
|  | 			    term_variables( State, Vars), | ||
|  | 			    'chr none_locked'( Vars), | ||
|  | 			    Store = yes | ||
|  | 			; State == removed ->			% the price for eager removal ... | ||
|  | 			    chr_indexed_variables(Susp,Vars), | ||
|  | 			    Store = yes | ||
|  | 			; | ||
|  | 			    Vars = [], | ||
|  | 			    Store = no | ||
|  | 			) | ||
|  | 	). | ||
|  | 
 | ||
|  | generate_allocate_clause(AllocateClause) :- | ||
|  | 	AllocateClause = | ||
|  | 	( | ||
|  | 		allocate_constraint( Closure, Self, F, Args) :- | ||
|  | 			Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args], | ||
|  | 			'chr create_mutable'(0,Gref), % Gref = mutable(0), | ||
|  | 			'chr empty_history'(History), | ||
|  | 			'chr create_mutable'(History,Href), % Href = mutable(History), | ||
|  | 			chr_indexed_variables(Self,Vars), | ||
|  | 			'chr create_mutable'(passive(Vars),Mref), % Mref = mutable(passive(Vars)), | ||
|  | 			'chr gen_id'( Id) | ||
|  | 	). | ||
|  | 
 | ||
|  | generate_insert_constraint_internal(Clause) :- | ||
|  | 	Clause = | ||
|  | 	( | ||
|  | 		insert_constraint_internal(yes, Vars, Self, Closure, F, Args) :- | ||
|  | 			Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args], | ||
|  | 			chr_indexed_variables(Self,Vars), | ||
|  | 			'chr none_locked'(Vars), | ||
|  | 			'chr create_mutable'(active,Mref), % Mref = mutable(active), | ||
|  | 			'chr create_mutable'(0,Gref), % Gref = mutable(0), | ||
|  | 			'chr empty_history'(History), | ||
|  | 			'chr create_mutable'(History,Href), % Href = mutable(History), | ||
|  | 			'chr gen_id'(Id) | ||
|  | 	). | ||
|  | 
 | ||
|  | global_indexed_variables_clause(Constraints,Clause) :- | ||
|  | 	( forsome(C,Constraints,chr_translate:may_trigger(C)) -> | ||
|  | 		Body = (Susp =.. [_,_,_,_,_,_,Term|_], '$indexed_variables'(Term,Vars)) | ||
|  | 	; | ||
|  | 		Body = true, | ||
|  | 		Vars = [] | ||
|  | 	), | ||
|  | 	Clause = ( chr_indexed_variables(Susp,Vars) :- Body ). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | generate_attach_increment(Clauses) :- | ||
|  | 	get_max_constraint_index(N), | ||
|  | 	( N > 0 -> | ||
|  | 		Clauses = [Clause1,Clause2], | ||
|  | 		generate_attach_increment_empty(Clause1), | ||
|  | 		( N == 1 -> | ||
|  | 			generate_attach_increment_one(Clause2) | ||
|  | 		; | ||
|  | 			generate_attach_increment_many(N,Clause2) | ||
|  | 		) | ||
|  | 	; | ||
|  | 		Clauses = [] | ||
|  | 	). | ||
|  | 
 | ||
|  | generate_attach_increment_empty((attach_increment([],_) :- true)). | ||
|  | 
 | ||
|  | generate_attach_increment_one(Clause) :- | ||
|  | 	Head = attach_increment([Var|Vars],Susps), | ||
|  | 	get_target_module(Mod), | ||
|  | 	Body = | ||
|  | 	( | ||
|  | 		'chr not_locked'(Var), | ||
|  | 		( get_attr(Var,Mod,VarSusps) -> | ||
|  | 			sort(VarSusps,SortedVarSusps), | ||
|  | 			merge(Susps,SortedVarSusps,MergedSusps), | ||
|  | 			put_attr(Var,Mod,MergedSusps) | ||
|  | 		; | ||
|  | 			put_attr(Var,Mod,Susps) | ||
|  | 		), | ||
|  | 		attach_increment(Vars,Susps) | ||
|  | 	), | ||
|  | 	Clause = (Head :- Body). | ||
|  | 
 | ||
|  | generate_attach_increment_many(N,Clause) :- | ||
|  | 	make_attr(N,Mask,SuspsList,Attr), | ||
|  | 	make_attr(N,OtherMask,OtherSuspsList,OtherAttr), | ||
|  | 	Head = attach_increment([Var|Vars],Attr), | ||
|  | 	bagof(G,X ^ Y ^ SY ^ M ^ (member2(SuspsList,OtherSuspsList,X-Y),G = (sort(Y,SY),'chr merge_attributes'(X,SY,M))),Gs), | ||
|  | 	list2conj(Gs,SortGoals), | ||
|  | 	bagof(MS,A ^ B ^ C ^ member((A,'chr merge_attributes'(B,C,MS)),Gs), MergedSuspsList), | ||
|  | 	make_attr(N,MergedMask,MergedSuspsList,NewAttr), | ||
|  | 	get_target_module(Mod), | ||
|  | 	Body = | ||
|  | 	( | ||
|  | 		'chr not_locked'(Var), | ||
|  | 		( get_attr(Var,Mod,TOtherAttr) -> | ||
|  | 			TOtherAttr = OtherAttr, | ||
|  | 			SortGoals, | ||
|  | 			MergedMask is Mask \/ OtherMask, | ||
|  | 			put_attr(Var,Mod,NewAttr) | ||
|  | 		; | ||
|  | 			put_attr(Var,Mod,Attr) | ||
|  | 		), | ||
|  | 		attach_increment(Vars,Attr) | ||
|  | 	), | ||
|  | 	Clause = (Head :- Body). | ||
|  | 
 | ||
|  | %%	attr_unify_hook | ||
|  | generate_attr_unify_hook([Clause]) :- | ||
|  | 	get_max_constraint_index(N), | ||
|  | 	( N == 0 -> | ||
|  | 		get_target_module(Mod), | ||
|  | 		Clause = | ||
|  | 		( attr_unify_hook(Attr,Var) :- | ||
|  | 			write('ERROR: Unexpected triggering of attr_unify_hook/2 in module '), | ||
|  | 			writeln(Mod) | ||
|  | 		) | ||
|  | 	; N == 1 -> | ||
|  | 		generate_attr_unify_hook_one(Clause) | ||
|  | 	; | ||
|  | 		generate_attr_unify_hook_many(N,Clause) | ||
|  | 	). | ||
|  | 
 | ||
|  | generate_attr_unify_hook_one(Clause) :- | ||
|  | 	Head = attr_unify_hook(Susps,Other), | ||
|  | 	get_target_module(Mod), | ||
|  | 	make_run_suspensions(NewSusps,WakeNewSusps), | ||
|  | 	make_run_suspensions(Susps,WakeSusps), | ||
|  | 	Body = | ||
|  | 	( | ||
|  | 		sort(Susps, SortedSusps), | ||
|  | 		( var(Other) -> | ||
|  | 			( get_attr(Other,Mod,OtherSusps) -> | ||
|  | 				true | ||
|  | 			; | ||
|  | 				OtherSusps = [] | ||
|  | 			), | ||
|  | 			sort(OtherSusps,SortedOtherSusps), | ||
|  | 			'chr merge_attributes'(SortedSusps,SortedOtherSusps,NewSusps), | ||
|  | 			put_attr(Other,Mod,NewSusps), | ||
|  | 			WakeNewSusps | ||
|  | 		; | ||
|  | 			( compound(Other) -> | ||
|  | 				term_variables(Other,OtherVars), | ||
|  | 				attach_increment(OtherVars, SortedSusps) | ||
|  | 			; | ||
|  | 				true | ||
|  | 			), | ||
|  | 			WakeSusps | ||
|  | 		) | ||
|  | 	), | ||
|  | 	Clause = (Head :- Body). | ||
|  | 
 | ||
|  | generate_attr_unify_hook_many(N,Clause) :- | ||
|  | 	make_attr(N,Mask,SuspsList,Attr), | ||
|  | 	make_attr(N,OtherMask,OtherSuspsList,OtherAttr), | ||
|  | 	bagof(Sort,A ^ B ^ ( member(A,SuspsList) , Sort = sort(A,B) ) , SortGoalList), | ||
|  | 	list2conj(SortGoalList,SortGoals), | ||
|  | 	bagof(B, A ^ member(sort(A,B),SortGoalList), SortedSuspsList), | ||
|  | 	bagof(C, D ^ E ^ F ^ G ^ (member2(SortedSuspsList,OtherSuspsList,D-E), | ||
|  |                                   C = (sort(E,F), | ||
|  |                                        'chr merge_attributes'(D,F,G)) ), | ||
|  |               SortMergeGoalList), | ||
|  | 	bagof(G, D ^ F ^ H ^ member((H,'chr merge_attributes'(D,F,G)),SortMergeGoalList) , MergedSuspsList), | ||
|  | 	list2conj(SortMergeGoalList,SortMergeGoals), | ||
|  | 	make_attr(N,MergedMask,MergedSuspsList,MergedAttr), | ||
|  | 	make_attr(N,Mask,SortedSuspsList,SortedAttr), | ||
|  | 	Head = attr_unify_hook(Attr,Other), | ||
|  | 	get_target_module(Mod), | ||
|  | 	make_run_suspensions_loop(MergedSuspsList,WakeMergedSusps), | ||
|  | 	make_run_suspensions_loop(SortedSuspsList,WakeSortedSusps), | ||
|  | 	Body = | ||
|  | 	( | ||
|  | 		SortGoals, | ||
|  | 		( var(Other) -> | ||
|  | 			( get_attr(Other,Mod,TOtherAttr) -> | ||
|  | 				TOtherAttr = OtherAttr, | ||
|  | 				SortMergeGoals, | ||
|  | 				MergedMask is Mask \/ OtherMask, | ||
|  | 				put_attr(Other,Mod,MergedAttr), | ||
|  | 				WakeMergedSusps | ||
|  | 			; | ||
|  | 				put_attr(Other,Mod,SortedAttr), | ||
|  | 				WakeSortedSusps | ||
|  | 			) | ||
|  | 		; | ||
|  | 			( compound(Other) -> | ||
|  | 				term_variables(Other,OtherVars), | ||
|  | 				attach_increment(OtherVars,SortedAttr) | ||
|  | 			; | ||
|  | 				true | ||
|  | 			), | ||
|  | 			WakeSortedSusps | ||
|  | 		) | ||
|  | 	), | ||
|  | 	Clause = (Head :- Body). | ||
|  | 
 | ||
|  | make_run_suspensions(Susps,Goal) :- | ||
|  | 	( chr_pp_flag(debugable,on) -> | ||
|  | 		Goal = 'chr run_suspensions_d'(Susps) | ||
|  | 	; | ||
|  | 		Goal = 'chr run_suspensions'(Susps) | ||
|  | 	). | ||
|  | 
 | ||
|  | make_run_suspensions_loop(SuspsList,Goal) :- | ||
|  | 	( chr_pp_flag(debugable,on) -> | ||
|  | 		Goal = 'chr run_suspensions_loop_d'(SuspsList) | ||
|  | 	; | ||
|  | 		Goal = 'chr run_suspensions_loop'(SuspsList) | ||
|  | 	). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | % $insert_in_store_F/A | ||
|  | % $delete_from_store_F/A | ||
|  | 
 | ||
|  | generate_insert_delete_constraints([],[]). | ||
|  | generate_insert_delete_constraints([FA|Rest],Clauses) :- | ||
|  | 	( is_attached(FA) -> | ||
|  | 		Clauses = [IClause,DClause|RestClauses], | ||
|  | 		generate_insert_delete_constraint(FA,IClause,DClause) | ||
|  | 	; | ||
|  | 		Clauses = RestClauses | ||
|  | 	), | ||
|  | 	generate_insert_delete_constraints(Rest,RestClauses). | ||
|  | 
 | ||
|  | generate_insert_delete_constraint(FA,IClause,DClause) :- | ||
|  | 	get_store_type(FA,StoreType), | ||
|  | 	generate_insert_constraint(StoreType,FA,IClause), | ||
|  | 	generate_delete_constraint(StoreType,FA,DClause). | ||
|  | 
 | ||
|  | generate_insert_constraint(StoreType,C,Clause) :- | ||
|  | 	make_name('$insert_in_store_',C,ClauseName), | ||
|  | 	Head =.. [ClauseName,Susp], | ||
|  | 	generate_insert_constraint_body(StoreType,C,Susp,Body), | ||
|  | 	Clause = (Head :- Body). | ||
|  | 
 | ||
|  | generate_insert_constraint_body(default,C,Susp,Body) :- | ||
|  | 	get_target_module(Mod), | ||
|  | 	get_max_constraint_index(Total), | ||
|  | 	( Total == 1 -> | ||
|  | 		generate_attach_body_1(C,Store,Susp,AttachBody) | ||
|  | 	; | ||
|  | 		generate_attach_body_n(C,Store,Susp,AttachBody) | ||
|  | 	), | ||
|  | 	Body = | ||
|  | 	( | ||
|  | 		'chr default_store'(Store), | ||
|  | 		AttachBody | ||
|  | 	). | ||
|  | generate_insert_constraint_body(multi_hash(Indexes),C,Susp,Body) :- | ||
|  | 	generate_multi_hash_insert_constraint_bodies(Indexes,C,Susp,Body). | ||
|  | generate_insert_constraint_body(global_ground,C,Susp,Body) :- | ||
|  | 	global_ground_store_name(C,StoreName), | ||
|  | 	make_get_store_goal(StoreName,Store,GetStoreGoal), | ||
|  | 	make_update_store_goal(StoreName,[Susp|Store],UpdateStoreGoal), | ||
|  | 	Body = | ||
|  | 	( | ||
|  | 		GetStoreGoal,     % nb_getval(StoreName,Store), | ||
|  | 		UpdateStoreGoal   % b_setval(StoreName,[Susp|Store]) | ||
|  | 	). | ||
|  | generate_insert_constraint_body(multi_store(StoreTypes),C,Susp,Body) :- | ||
|  | 	find_with_var_identity( | ||
|  | 		B, | ||
|  | 		[Susp], | ||
|  | 		( | ||
|  | 			member(ST,StoreTypes), | ||
|  | 			chr_translate:generate_insert_constraint_body(ST,C,Susp,B) | ||
|  | 		), | ||
|  | 		Bodies | ||
|  | 		), | ||
|  | 	list2conj(Bodies,Body). | ||
|  | 
 | ||
|  | generate_multi_hash_insert_constraint_bodies([],_,_,true). | ||
|  | generate_multi_hash_insert_constraint_bodies([Index|Indexes],FA,Susp,(Body,Bodies)) :- | ||
|  | 	multi_hash_store_name(FA,Index,StoreName), | ||
|  | 	multi_hash_key(FA,Index,Susp,KeyBody,Key), | ||
|  | 	make_get_store_goal(StoreName,Store,GetStoreGoal), | ||
|  | 	Body = | ||
|  | 	( | ||
|  | 		KeyBody, | ||
|  | 	        GetStoreGoal, % nb_getval(StoreName,Store), | ||
|  | 		insert_ht(Store,Key,Susp) | ||
|  | 	), | ||
|  | 	generate_multi_hash_insert_constraint_bodies(Indexes,FA,Susp,Bodies). | ||
|  | 
 | ||
|  | generate_delete_constraint(StoreType,FA,Clause) :- | ||
|  | 	make_name('$delete_from_store_',FA,ClauseName), | ||
|  | 	Head =.. [ClauseName,Susp], | ||
|  | 	generate_delete_constraint_body(StoreType,FA,Susp,Body), | ||
|  | 	Clause = (Head :- Body). | ||
|  | 
 | ||
|  | generate_delete_constraint_body(default,C,Susp,Body) :- | ||
|  | 	get_target_module(Mod), | ||
|  | 	get_max_constraint_index(Total), | ||
|  | 	( Total == 1 -> | ||
|  | 		generate_detach_body_1(C,Store,Susp,DetachBody), | ||
|  | 		Body = | ||
|  | 		( | ||
|  | 			'chr default_store'(Store), | ||
|  | 			DetachBody | ||
|  | 		) | ||
|  | 	; | ||
|  | 		generate_detach_body_n(C,Store,Susp,DetachBody), | ||
|  | 		Body = | ||
|  | 		( | ||
|  | 			'chr default_store'(Store), | ||
|  | 			DetachBody | ||
|  | 		) | ||
|  | 	). | ||
|  | generate_delete_constraint_body(multi_hash(Indexes),C,Susp,Body) :- | ||
|  | 	generate_multi_hash_delete_constraint_bodies(Indexes,C,Susp,Body). | ||
|  | generate_delete_constraint_body(global_ground,C,Susp,Body) :- | ||
|  | 	global_ground_store_name(C,StoreName), | ||
|  | 	make_get_store_goal(StoreName,Store,GetStoreGoal), | ||
|  | 	make_update_store_goal(StoreName,NStore,UpdateStoreGoal), | ||
|  | 	Body = | ||
|  | 	( | ||
|  | 		GetStoreGoal, % nb_getval(StoreName,Store), | ||
|  | 		'chr sbag_del_element'(Store,Susp,NStore), | ||
|  | 		UpdateStoreGoal % b_setval(StoreName,NStore) | ||
|  | 	). | ||
|  | generate_delete_constraint_body(multi_store(StoreTypes),C,Susp,Body) :- | ||
|  | 	find_with_var_identity( | ||
|  | 		B, | ||
|  | 		[Susp], | ||
|  | 		( | ||
|  | 			member(ST,StoreTypes), | ||
|  | 			chr_translate:generate_delete_constraint_body(ST,C,Susp,B) | ||
|  | 		), | ||
|  | 		Bodies | ||
|  | 	), | ||
|  | 	list2conj(Bodies,Body). | ||
|  | 
 | ||
|  | generate_multi_hash_delete_constraint_bodies([],_,_,true). | ||
|  | generate_multi_hash_delete_constraint_bodies([Index|Indexes],FA,Susp,(Body,Bodies)) :- | ||
|  | 	multi_hash_store_name(FA,Index,StoreName), | ||
|  | 	multi_hash_key(FA,Index,Susp,KeyBody,Key), | ||
|  | 	make_get_store_goal(StoreName,Store,GetStoreGoal), | ||
|  | 	Body = | ||
|  | 	( | ||
|  | 		KeyBody, | ||
|  | 		GetStoreGoal, % nb_getval(StoreName,Store), | ||
|  | 		delete_ht(Store,Key,Susp) | ||
|  | 	), | ||
|  | 	generate_multi_hash_delete_constraint_bodies(Indexes,FA,Susp,Bodies). | ||
|  | 
 | ||
|  | generate_delete_constraint_call(FA,Susp,Call) :- | ||
|  | 	make_name('$delete_from_store_',FA,Functor), | ||
|  | 	Call =.. [Functor,Susp]. | ||
|  | 
 | ||
|  | generate_insert_constraint_call(FA,Susp,Call) :- | ||
|  | 	make_name('$insert_in_store_',FA,Functor), | ||
|  | 	Call =.. [Functor,Susp]. | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | generate_store_code(Constraints,[Enumerate|L]) :- | ||
|  | 	enumerate_stores_code(Constraints,Enumerate), | ||
|  | 	generate_store_code(Constraints,L,[]). | ||
|  | 
 | ||
|  | generate_store_code([],L,L). | ||
|  | generate_store_code([C|Cs],L,T) :- | ||
|  | 	get_store_type(C,StoreType), | ||
|  | 	generate_store_code(StoreType,C,L,L1), | ||
|  | 	generate_store_code(Cs,L1,T). | ||
|  | 
 | ||
|  | generate_store_code(default,_,L,L). | ||
|  | generate_store_code(multi_hash(Indexes),C,L,T) :- | ||
|  | 	multi_hash_store_initialisations(Indexes,C,L,L1), | ||
|  | 	multi_hash_via_lookups(Indexes,C,L1,T). | ||
|  | generate_store_code(global_ground,C,L,T) :- | ||
|  | 	global_ground_store_initialisation(C,L,T). | ||
|  | generate_store_code(multi_store(StoreTypes),C,L,T) :- | ||
|  | 	multi_store_generate_store_code(StoreTypes,C,L,T). | ||
|  | 
 | ||
|  | multi_store_generate_store_code([],_,L,L). | ||
|  | multi_store_generate_store_code([ST|STs],C,L,T) :- | ||
|  | 	generate_store_code(ST,C,L,L1), | ||
|  | 	multi_store_generate_store_code(STs,C,L1,T). | ||
|  | 
 | ||
|  | multi_hash_store_initialisations([],_,L,L). | ||
|  | multi_hash_store_initialisations([Index|Indexes],FA,L,T) :- | ||
|  | 	multi_hash_store_name(FA,Index,StoreName), | ||
|  | 	make_init_store_goal(StoreName,HT,InitStoreGoal), | ||
|  | 	L = [(:- (new_ht(HT),InitStoreGoal)) | L1], | ||
|  | 	multi_hash_store_initialisations(Indexes,FA,L1,T). | ||
|  | 
 | ||
|  | global_ground_store_initialisation(C,L,T) :- | ||
|  | 	global_ground_store_name(C,StoreName), | ||
|  | 	make_init_store_goal(StoreName,[],InitStoreGoal), | ||
|  | 	L = [(:- InitStoreGoal)|T]. | ||
|  | 
 | ||
|  | multi_hash_via_lookups([],_,L,L). | ||
|  | multi_hash_via_lookups([Index|Indexes],C,L,T) :- | ||
|  | 	multi_hash_via_lookup_name(C,Index,PredName), | ||
|  | 	Head =.. [PredName,Key,SuspsList], | ||
|  | 	multi_hash_store_name(C,Index,StoreName), | ||
|  | 	make_get_store_goal(StoreName,HT,GetStoreGoal), | ||
|  | 	Body = | ||
|  | 	( | ||
|  | 		GetStoreGoal, % nb_getval(StoreName,HT), | ||
|  | 		lookup_ht(HT,Key,SuspsList) | ||
|  | 	), | ||
|  | 	L = [(Head :- Body)|L1], | ||
|  | 	multi_hash_via_lookups(Indexes,C,L1,T). | ||
|  | 
 | ||
|  | multi_hash_via_lookup_name(F/A,Index,Name) :- | ||
|  | 	( integer(Index) -> | ||
|  | 		IndexName = Index | ||
|  | 	; is_list(Index) -> | ||
|  | 		atom_concat_list(Index,IndexName) | ||
|  | 	), | ||
|  | 	atom_concat_list(['$via1_multi_hash_',F,(/),A,'-',IndexName],Name). | ||
|  | 
 | ||
|  | multi_hash_store_name(F/A,Index,Name) :- | ||
|  | 	get_target_module(Mod), | ||
|  | 	( integer(Index) -> | ||
|  | 		IndexName = Index | ||
|  | 	; is_list(Index) -> | ||
|  | 		atom_concat_list(Index,IndexName) | ||
|  | 	), | ||
|  | 	atom_concat_list(['$chr_store_multi_hash_',Mod,(:),F,(/),A,'-',IndexName],Name). | ||
|  | 
 | ||
|  | multi_hash_key(F/A,Index,Susp,KeyBody,Key) :- | ||
|  | 	( ( integer(Index) -> | ||
|  | 		I = Index | ||
|  | 	  ; | ||
|  | 		Index = [I] | ||
|  | 	  ) -> | ||
|  | 		SuspIndex is I + 6, | ||
|  | 		KeyBody = arg(SuspIndex,Susp,Key) | ||
|  | 	; is_list(Index) -> | ||
|  | 		sort(Index,Indexes), | ||
|  | 		find_with_var_identity(arg(J,Susp,KeyI)-KeyI,[Susp],(member(I,Indexes),J is I + 6),ArgKeyPairs), | ||
|  | 		pairup(Bodies,Keys,ArgKeyPairs), | ||
|  | 		Key =.. [k|Keys], | ||
|  | 		list2conj(Bodies,KeyBody) | ||
|  | 	). | ||
|  | 
 | ||
|  | multi_hash_key_args(Index,Head,KeyArgs) :- | ||
|  | 	( integer(Index) -> | ||
|  | 		arg(Index,Head,Arg), | ||
|  | 		KeyArgs = [Arg] | ||
|  | 	; is_list(Index) -> | ||
|  | 		sort(Index,Indexes), | ||
|  | 		term_variables(Head,Vars), | ||
|  | 		find_with_var_identity(Arg,Vars,(member(I,Indexes), arg(I,Head,Arg)),KeyArgs) | ||
|  | 	). | ||
|  | 
 | ||
|  | global_ground_store_name(F/A,Name) :- | ||
|  | 	get_target_module(Mod), | ||
|  | 	atom_concat_list(['$chr_store_global_ground_',Mod,(:),F,(/),A],Name). | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | enumerate_stores_code(Constraints,Clause) :- | ||
|  | 	Head = '$enumerate_suspensions'(Susp), | ||
|  | 	enumerate_store_bodies(Constraints,Susp,Bodies), | ||
|  | 	list2disj(Bodies,Body), | ||
|  | 	Clause = (Head :- Body). | ||
|  | 
 | ||
|  | enumerate_store_bodies([],_,[]). | ||
|  | enumerate_store_bodies([C|Cs],Susp,L) :- | ||
|  | 	( is_attached(C) -> | ||
|  | 		get_store_type(C,StoreType), | ||
|  | 		enumerate_store_body(StoreType,C,Susp,B), | ||
|  | 		L = [B|T] | ||
|  | 	; | ||
|  | 		L = T | ||
|  | 	), | ||
|  | 	enumerate_store_bodies(Cs,Susp,T). | ||
|  | 
 | ||
|  | enumerate_store_body(default,C,Susp,Body) :- | ||
|  | 	get_constraint_index(C,Index), | ||
|  | 	get_target_module(Mod), | ||
|  | 	get_max_constraint_index(MaxIndex), | ||
|  | 	Body1 = | ||
|  | 	( | ||
|  | 		'chr default_store'(GlobalStore), | ||
|  | 		get_attr(GlobalStore,Mod,Attr) | ||
|  | 	), | ||
|  | 	( MaxIndex > 1 -> | ||
|  | 		NIndex is Index + 1, | ||
|  | 		Body2 = | ||
|  | 		( | ||
|  | 			arg(NIndex,Attr,List), | ||
|  | 			'chr sbag_member'(Susp,List) | ||
|  | 		) | ||
|  | 	; | ||
|  | 		Body2 = 'chr sbag_member'(Susp,Attr) | ||
|  | 	), | ||
|  | 	Body = (Body1,Body2). | ||
|  | enumerate_store_body(multi_hash([Index|_]),C,Susp,Body) :- | ||
|  | 	multi_hash_enumerate_store_body(Index,C,Susp,Body). | ||
|  | enumerate_store_body(global_ground,C,Susp,Body) :- | ||
|  | 	global_ground_store_name(C,StoreName), | ||
|  | 	make_get_store_goal(StoreName,List,GetStoreGoal), | ||
|  | 	Body = | ||
|  | 	( | ||
|  | 		GetStoreGoal, % nb_getval(StoreName,List), | ||
|  | 		'chr sbag_member'(Susp,List) | ||
|  | 	). | ||
|  | enumerate_store_body(multi_store(STs),C,Susp,Body) :- | ||
|  | 	once(( | ||
|  | 		member(ST,STs), | ||
|  | 		enumerate_store_body(ST,C,Susp,Body) | ||
|  | 	)). | ||
|  | 
 | ||
|  | multi_hash_enumerate_store_body(I,C,Susp,B) :- | ||
|  | 	multi_hash_store_name(C,I,StoreName), | ||
|  | 	make_get_store_goal(StoreName,HT,GetStoreGoal), | ||
|  | 	B = | ||
|  | 	( | ||
|  | 		GetStoreGoal, % nb_getval(StoreName,HT), | ||
|  | 		value_ht(HT,Susp) | ||
|  | 	). | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | check_attachments(Constraints) :- | ||
|  | 	( chr_pp_flag(check_attachments,on) -> | ||
|  | 		check_constraint_attachments(Constraints) | ||
|  | 	; | ||
|  | 		true | ||
|  | 	). | ||
|  | 
 | ||
|  | check_constraint_attachments([]). | ||
|  | check_constraint_attachments([C|Cs]) :- | ||
|  | 	check_constraint_attachment(C), | ||
|  | 	check_constraint_attachments(Cs). | ||
|  | 
 | ||
|  | check_constraint_attachment(C) :- | ||
|  | 	get_max_occurrence(C,MO), | ||
|  | 	check_occurrences_attachment(C,1,MO). | ||
|  | 
 | ||
|  | check_occurrences_attachment(C,O,MO) :- | ||
|  | 	( O > MO -> | ||
|  | 		true | ||
|  | 	; | ||
|  | 		check_occurrence_attachment(C,O), | ||
|  | 		NO is O + 1, | ||
|  | 		check_occurrences_attachment(C,NO,MO) | ||
|  | 	). | ||
|  | 
 | ||
|  | check_occurrence_attachment(C,O) :- | ||
|  | 	get_occurrence(C,O,RuleNb,ID), | ||
|  | 	get_rule(RuleNb,PragmaRule), | ||
|  | 	PragmaRule = pragma(rule(Heads1,Heads2,Guard,Body),ids(IDs1,IDs2),_,_,_), | ||
|  | 	( select2(ID,Head1,IDs1,Heads1,RIDs1,RHeads1) -> | ||
|  | 		check_attachment_head1(Head1,ID,RuleNb,Heads1,Heads2,Guard) | ||
|  | 	; select2(ID,Head2,IDs2,Heads2,RIDs2,RHeads2) -> | ||
|  | 		check_attachment_head2(Head2,ID,RuleNb,Heads1,Body) | ||
|  | 	). | ||
|  | 
 | ||
|  | check_attachment_head1(C,ID,RuleNb,H1,H2,G) :- | ||
|  | 	functor(C,F,A), | ||
|  | 	( H1 == [C], | ||
|  | 	  H2 == [], | ||
|  | 	  G == true, | ||
|  | 	  C =.. [_|L], | ||
|  | 	  no_matching(L,[]), | ||
|  | 	  \+ is_passive(RuleNb,ID) -> | ||
|  | 		attached(F/A,no) | ||
|  | 	; | ||
|  | 		attached(F/A,maybe) | ||
|  | 	). | ||
|  | 
 | ||
|  | no_matching([],_). | ||
|  | no_matching([X|Xs],Prev) :- | ||
|  | 	var(X), | ||
|  | 	\+ memberchk_eq(X,Prev), | ||
|  | 	no_matching(Xs,[X|Prev]). | ||
|  | 
 | ||
|  | check_attachment_head2(C,ID,RuleNb,H1,B) :- | ||
|  | 	functor(C,F,A), | ||
|  | 	( is_passive(RuleNb,ID) -> | ||
|  | 		attached(F/A,maybe) | ||
|  | 	; H1 \== [], | ||
|  | 	  B == true -> | ||
|  | 		attached(F/A,maybe) | ||
|  | 	; | ||
|  | 		attached(F/A,yes) | ||
|  | 	). | ||
|  | 
 | ||
|  | all_attached([]). | ||
|  | all_attached([C|Cs]) :- | ||
|  | 	functor(C,F,A), | ||
|  | 	is_attached(F/A), | ||
|  | 	all_attached(Cs). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | set_constraint_indices([],M) :- | ||
|  | 	N is M - 1, | ||
|  | 	max_constraint_index(N). | ||
|  | set_constraint_indices([C|Cs],N) :- | ||
|  | 	( ( may_trigger(C) ;  is_attached(C), get_store_type(C,default)) -> | ||
|  | 		constraint_index(C,N), | ||
|  | 		M is N + 1, | ||
|  | 		set_constraint_indices(Cs,M) | ||
|  | 	; | ||
|  | 		set_constraint_indices(Cs,N) | ||
|  | 	). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %%  ____        _         ____                      _ _       _   _ | ||
|  | %% |  _ \ _   _| | ___   / ___|___  _ __ ___  _ __ (_) | __ _| |_(_) ___  _ __ | ||
|  | %% | |_) | | | | |/ _ \ | |   / _ \| '_ ` _ \| '_ \| | |/ _` | __| |/ _ \| '_ \ | ||
|  | %% |  _ <| |_| | |  __/ | |__| (_) | | | | | | |_) | | | (_| | |_| | (_) | | | | | ||
|  | %% |_| \_\\__,_|_|\___|  \____\___/|_| |_| |_| .__/|_|_|\__,_|\__|_|\___/|_| |_| | ||
|  | %%                                           |_| | ||
|  | 
 | ||
|  | constraints_code(Constraints,Rules,Clauses) :- | ||
|  | 	post_constraints(Constraints,1), | ||
|  | 	constraints_code1(1,Rules,L,[]), | ||
|  | 	clean_clauses(L,Clauses). | ||
|  | 
 | ||
|  | %%	Add global data | ||
|  | post_constraints([],MaxIndex1) :- | ||
|  | 	MaxIndex is MaxIndex1 - 1, | ||
|  | 	constraint_count(MaxIndex). | ||
|  | post_constraints([F/A|Cs],N) :- | ||
|  | 	constraint(F/A,N), | ||
|  | 	M is N + 1, | ||
|  | 	post_constraints(Cs,M). | ||
|  | constraints_code1(I,Rules,L,T) :- | ||
|  | 	get_constraint_count(N), | ||
|  | 	( I > N -> | ||
|  | 		T = L | ||
|  | 	; | ||
|  | 		constraint_code(I,Rules,L,T1), | ||
|  | 		J is I + 1, | ||
|  | 		constraints_code1(J,Rules,T1,T) | ||
|  | 	). | ||
|  | 
 | ||
|  | %%	Generate code for a single CHR constraint | ||
|  | constraint_code(I, Rules, L, T) :- | ||
|  | 	get_constraint(Constraint,I), | ||
|  | 	constraint_prelude(Constraint,Clause), | ||
|  | 	L = [Clause | L1], | ||
|  | 	Id1 = [0], | ||
|  | 	rules_code(Rules,I,Id1,Id2,L1,L2), | ||
|  | 	gen_cond_attach_clause(Constraint,Id2,L2,T). | ||
|  | 
 | ||
|  | %%	Generate prelude predicate for a constraint. | ||
|  | %%	f(...) :- f/a_0(...,Susp). | ||
|  | constraint_prelude(F/A, Clause) :- | ||
|  | 	vars_susp(A,Vars,Susp,VarsSusp), | ||
|  | 	Head =.. [ F | Vars], | ||
|  | 	build_head(F,A,[0],VarsSusp,Delegate), | ||
|  | 	get_target_module(Mod), | ||
|  | 	FTerm =.. [F|Vars], | ||
|  | 	( chr_pp_flag(debugable,on) -> | ||
|  | 		Clause = | ||
|  | 			( Head :- | ||
|  | 				allocate_constraint(Mod : Delegate, Susp, FTerm, Vars), | ||
|  | 			        ( | ||
|  | 					'chr debug_event'(call(Susp)), | ||
|  | 			                Delegate | ||
|  | 				; | ||
|  | 					'chr debug_event'(fail(Susp)), !, | ||
|  | 					fail | ||
|  | 				), | ||
|  | 			        ( | ||
|  | 					'chr debug_event'(exit(Susp)) | ||
|  | 			        ; | ||
|  | 					'chr debug_event'(redo(Susp)), | ||
|  | 				        fail | ||
|  | 			        ) | ||
|  | 			) | ||
|  | 	; | ||
|  | 		Clause = ( Head  :- Delegate ) | ||
|  | 	). | ||
|  | 
 | ||
|  | gen_cond_attach_clause(F/A,Id,L,T) :- | ||
|  | 	( is_attached(F/A) -> | ||
|  | 		( Id == [0] -> | ||
|  | 			( may_trigger(F/A) -> | ||
|  | 				gen_cond_attach_goal(F/A,Body,AllArgs,Args,Susp) | ||
|  | 			; | ||
|  | 				gen_insert_constraint_internal_goal(F/A,Body,AllArgs,Args,Susp) | ||
|  | 			) | ||
|  | 		;	vars_susp(A,Args,Susp,AllArgs), | ||
|  | 			gen_uncond_attach_goal(F/A,Susp,Body,_) | ||
|  | 		), | ||
|  | 		( chr_pp_flag(debugable,on) -> | ||
|  | 			Constraint =.. [F|Args], | ||
|  | 			DebugEvent = 'chr debug_event'(insert(Constraint#Susp)) | ||
|  | 		; | ||
|  | 			DebugEvent = true | ||
|  | 		), | ||
|  | 		build_head(F,A,Id,AllArgs,Head), | ||
|  | 		Clause = ( Head :- DebugEvent,Body ), | ||
|  | 		L = [Clause | T] | ||
|  | 	; | ||
|  | 		L = T | ||
|  | 	). | ||
|  | 
 | ||
|  | gen_cond_attach_goal(F/A,Goal,AllArgs,Args,Susp) :- | ||
|  | 	vars_susp(A,Args,Susp,AllArgs), | ||
|  | 	build_head(F,A,[0],AllArgs,Closure), | ||
|  | 	( may_trigger(F/A) -> | ||
|  | 		make_name('attach_',F/A,AttachF), | ||
|  | 		Attach =.. [AttachF,Vars,Susp] | ||
|  | 	; | ||
|  | 		Attach = true | ||
|  | 	), | ||
|  | 	get_target_module(Mod), | ||
|  | 	FTerm =.. [F|Args], | ||
|  | 	generate_insert_constraint_call(F/A,Susp,InsertCall), | ||
|  | 	Goal = | ||
|  | 	( | ||
|  | 		( var(Susp) -> | ||
|  | 			insert_constraint_internal(Stored,Vars,Susp,Mod:Closure,FTerm,Args) | ||
|  | 		; | ||
|  | 			activate_constraint(Stored,Vars,Susp,_) | ||
|  | 		), | ||
|  | 		( Stored == yes -> | ||
|  | 			InsertCall, | ||
|  | 			Attach | ||
|  | 		; | ||
|  | 			true | ||
|  | 		) | ||
|  | 	). | ||
|  | 
 | ||
|  | gen_insert_constraint_internal_goal(F/A,Goal,AllArgs,Args,Susp) :- | ||
|  | 	vars_susp(A,Args,Susp,AllArgs), | ||
|  | 	build_head(F,A,[0],AllArgs,Closure), | ||
|  | 	( may_trigger(F/A) -> | ||
|  | 		make_name('attach_',F/A,AttachF), | ||
|  | 		Attach =.. [AttachF,Vars,Susp] | ||
|  | 	; | ||
|  | 		Attach = true | ||
|  | 	), | ||
|  | 	get_target_module(Mod), | ||
|  | 	FTerm =.. [F|Args], | ||
|  | 	generate_insert_constraint_call(F/A,Susp,InsertCall), | ||
|  | 	Goal = | ||
|  | 	( | ||
|  | 		insert_constraint_internal(_,Vars,Susp,Mod:Closure,FTerm,Args), | ||
|  | 		InsertCall, | ||
|  | 		Attach | ||
|  | 	). | ||
|  | 
 | ||
|  | gen_uncond_attach_goal(FA,Susp,AttachGoal,Generation) :- | ||
|  | 	( may_trigger(FA) -> | ||
|  | 		make_name('attach_',FA,AttachF), | ||
|  | 		Attach =.. [AttachF,Vars,Susp] | ||
|  | 	; | ||
|  | 		Attach = true | ||
|  | 	), | ||
|  | 	generate_insert_constraint_call(FA,Susp,InsertCall), | ||
|  | 	AttachGoal = | ||
|  | 	( | ||
|  | 		activate_constraint(Stored,Vars, Susp, Generation), | ||
|  | 		( Stored == yes -> | ||
|  | 			InsertCall, | ||
|  | 			Attach | ||
|  | 		; | ||
|  | 			true | ||
|  | 		) | ||
|  | 	). | ||
|  | 
 | ||
|  | %%	Generate all the code for a constraint based on all CHR rules | ||
|  | rules_code([],_,Id,Id,L,L). | ||
|  | rules_code([R |Rs],I,Id1,Id3,L,T) :- | ||
|  | 	rule_code(R,I,Id1,Id2,L,T1), | ||
|  | 	rules_code(Rs,I,Id2,Id3,T1,T). | ||
|  | 
 | ||
|  | %%	Generate code for a constraint based on a single CHR rule | ||
|  | rule_code(PragmaRule,I,Id1,Id2,L,T) :- | ||
|  | 	PragmaRule = pragma(Rule,HeadIDs,_Pragmas,_Name,_RuleNb), | ||
|  | 	HeadIDs = ids(Head1IDs,Head2IDs), | ||
|  | 	Rule = rule(Head1,Head2,_,_), | ||
|  | 	heads1_code(Head1,[],Head1IDs,[],PragmaRule,I,Id1,L,L1), | ||
|  | 	heads2_code(Head2,[],Head2IDs,[],PragmaRule,I,Id1,Id2,L1,T). | ||
|  | 
 | ||
|  | %%	Generate code based on all the removed heads of a CHR rule | ||
|  | heads1_code([],_,_,_,_,_,_,L,L). | ||
|  | heads1_code([Head|Heads],RestHeads,[HeadID|HeadIDs],RestIDs,PragmaRule,I,Id,L,T) :- | ||
|  | 	PragmaRule = pragma(Rule,_,_Pragmas,_Name,RuleNb), | ||
|  | 	get_constraint(F/A,I), | ||
|  | 	( functor(Head,F,A), | ||
|  | 	  \+ is_passive(RuleNb,HeadID), | ||
|  | 	  \+ check_unnecessary_active(Head,RestHeads,Rule), | ||
|  | 	  all_attached(Heads), | ||
|  | 	  all_attached(RestHeads), | ||
|  | 	  Rule = rule(_,Heads2,_,_), | ||
|  | 	  all_attached(Heads2) -> | ||
|  | 		append(Heads,RestHeads,OtherHeads), | ||
|  | 		append(HeadIDs,RestIDs,OtherIDs), | ||
|  | 		head1_code(Head,OtherHeads,OtherIDs,PragmaRule,F/A,I,Id,L,L1) | ||
|  | 	; | ||
|  | 		L = L1 | ||
|  | 	), | ||
|  | 	heads1_code(Heads,[Head|RestHeads],HeadIDs,[HeadID|RestIDs],PragmaRule,I,Id,L1,T). | ||
|  | 
 | ||
|  | %%	Generate code based on one removed head of a CHR rule | ||
|  | head1_code(Head,OtherHeads,OtherIDs,PragmaRule,FA,I,Id,L,T) :- | ||
|  | 	PragmaRule = pragma(Rule,_,_,_Name,RuleNb), | ||
|  | 	Rule = rule(_,Head2,_,_), | ||
|  | 	( Head2 == [] -> | ||
|  | 		reorder_heads(RuleNb,Head,OtherHeads,OtherIDs,NOtherHeads,NOtherIDs), | ||
|  | 		simplification_code(Head,NOtherHeads,NOtherIDs,PragmaRule,FA,Id,L,T) | ||
|  | 	; | ||
|  | 		simpagation_head1_code(Head,OtherHeads,OtherIDs,PragmaRule,FA,Id,L,T) | ||
|  | 	). | ||
|  | 
 | ||
|  | %% Generate code based on all the persistent heads of a CHR rule | ||
|  | heads2_code([],_,_,_,_,_,Id,Id,L,L). | ||
|  | heads2_code([Head|Heads],RestHeads,[HeadID|HeadIDs],RestIDs,PragmaRule,I,Id1,Id3,L,T) :- | ||
|  | 	PragmaRule = pragma(Rule,_,_Pragmas,_Name,RuleNb), | ||
|  | 	get_constraint(F/A,I), | ||
|  | 	( functor(Head,F,A), | ||
|  | 	  \+ is_passive(RuleNb,HeadID), | ||
|  | 	  \+ check_unnecessary_active(Head,RestHeads,Rule), | ||
|  | 	  \+ set_semantics_rule(PragmaRule), | ||
|  | 	  all_attached(Heads), | ||
|  | 	  all_attached(RestHeads), | ||
|  | 	  Rule = rule(Heads1,_,_,_), | ||
|  | 	  all_attached(Heads1) -> | ||
|  | 		append(Heads,RestHeads,OtherHeads), | ||
|  | 		append(HeadIDs,RestIDs,OtherIDs), | ||
|  | 		length(Heads,RestHeadNb), | ||
|  | 		head2_code(Head,OtherHeads,OtherIDs,PragmaRule,RestHeadNb,F/A,Id1,L,L0), | ||
|  | 		inc_id(Id1,Id2), | ||
|  | 		gen_alloc_inc_clause(F/A,Id1,L0,L1) | ||
|  | 	; | ||
|  | 		L = L1, | ||
|  | 		Id2 = Id1 | ||
|  | 	), | ||
|  | 	heads2_code(Heads,[Head|RestHeads],HeadIDs,[HeadID|RestIDs],PragmaRule,I,Id2,Id3,L1,T). | ||
|  | 
 | ||
|  | %% Generate code based on one persistent head of a CHR rule | ||
|  | head2_code(Head,OtherHeads,OtherIDs,PragmaRule,RestHeadNb,FA,Id,L,T) :- | ||
|  | 	PragmaRule = pragma(Rule,_,_,_Name,RuleNb), | ||
|  | 	Rule = rule(Head1,_,_,_), | ||
|  | 	( Head1 == [] -> | ||
|  | 		reorder_heads(RuleNb,Head,OtherHeads,OtherIDs,NOtherHeads,_), | ||
|  | 		propagation_code(Head,NOtherHeads,Rule,RuleNb,RestHeadNb,FA,Id,L,T) | ||
|  | 	; | ||
|  | 		simpagation_head2_code(Head,OtherHeads,OtherIDs,PragmaRule,FA,Id,L,T) | ||
|  | 	). | ||
|  | 
 | ||
|  | gen_alloc_inc_clause(F/A,Id,L,T) :- | ||
|  | 	vars_susp(A,Vars,Susp,VarsSusp), | ||
|  | 	build_head(F,A,Id,VarsSusp,Head), | ||
|  | 	inc_id(Id,IncId), | ||
|  | 	build_head(F,A,IncId,VarsSusp,CallHead), | ||
|  | 	gen_allocation(Id,Vars,Susp,F/A,VarsSusp,ConditionalAlloc), | ||
|  | 	Clause = | ||
|  | 	( | ||
|  | 		Head :- | ||
|  | 			ConditionalAlloc, | ||
|  | 			CallHead | ||
|  | 	), | ||
|  | 	L = [Clause|T]. | ||
|  | 
 | ||
|  | gen_cond_allocation(Vars,Susp,FA,VarsSusp,ConstraintAllocationGoal) :- | ||
|  | 	gen_allocation(Vars,Susp,FA,VarsSusp,UncondConstraintAllocationGoal), | ||
|  | 	ConstraintAllocationGoal = | ||
|  | 	( var(Susp) -> | ||
|  | 	    UncondConstraintAllocationGoal | ||
|  | 	; | ||
|  | 	    true | ||
|  | 	). | ||
|  | gen_allocation(Vars,Susp,F/A,VarsSusp,ConstraintAllocationGoal) :- | ||
|  | 	build_head(F,A,[0],VarsSusp,Term), | ||
|  | 	get_target_module(Mod), | ||
|  | 	FTerm =.. [F|Vars], | ||
|  | 	ConstraintAllocationGoal = allocate_constraint(Mod : Term, Susp, FTerm, Vars). | ||
|  | 
 | ||
|  | gen_allocation(Id,Vars,Susp,FA,VarsSusp,ConstraintAllocationGoal) :- | ||
|  | 	( Id == [0] -> | ||
|  | 	    ( is_attached(FA) -> | ||
|  | 		( may_trigger(FA) -> | ||
|  | 			gen_cond_allocation(Vars,Susp,FA,VarsSusp,ConstraintAllocationGoal) | ||
|  | 		; | ||
|  | 			gen_allocation(Vars,Susp,FA,VarsSusp,ConstraintAllocationGoal) | ||
|  | 		) | ||
|  | 	    ; | ||
|  | 		ConstraintAllocationGoal = true | ||
|  | 	    ) | ||
|  | 	; | ||
|  | 		ConstraintAllocationGoal = true | ||
|  | 	). | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | guard_via_reschedule(Retrievals,GuardList,Prelude,Goal) :- | ||
|  | 	( chr_pp_flag(guard_via_reschedule,on) -> | ||
|  | 		guard_via_reschedule_main(Retrievals,GuardList,Prelude,Goal) | ||
|  | 	; | ||
|  | 		append(Retrievals,GuardList,GoalList), | ||
|  | 		list2conj(GoalList,Goal) | ||
|  | 	). | ||
|  | 
 | ||
|  | guard_via_reschedule_main(Retrievals,GuardList,Prelude,Goal) :- | ||
|  | 	initialize_unit_dictionary(Prelude,Dict), | ||
|  | 	build_units(Retrievals,GuardList,Dict,Units), | ||
|  | 	dependency_reorder(Units,NUnits), | ||
|  | 	units2goal(NUnits,Goal). | ||
|  | 
 | ||
|  | units2goal([],true). | ||
|  | units2goal([unit(_,Goal,_,_)|Units],(Goal,Goals)) :- | ||
|  | 	units2goal(Units,Goals). | ||
|  | 
 | ||
|  | dependency_reorder(Units,NUnits) :- | ||
|  | 	dependency_reorder(Units,[],NUnits). | ||
|  | 
 | ||
|  | dependency_reorder([],Acc,Result) :- | ||
|  | 	reverse(Acc,Result). | ||
|  | 
 | ||
|  | dependency_reorder([Unit|Units],Acc,Result) :- | ||
|  | 	Unit = unit(_GID,_Goal,Type,GIDs), | ||
|  | 	( Type == fixed -> | ||
|  | 		NAcc = [Unit|Acc] | ||
|  | 	; | ||
|  | 		dependency_insert(Acc,Unit,GIDs,NAcc) | ||
|  | 	), | ||
|  | 	dependency_reorder(Units,NAcc,Result). | ||
|  | 
 | ||
|  | dependency_insert([],Unit,_,[Unit]). | ||
|  | dependency_insert([X|Xs],Unit,GIDs,L) :- | ||
|  | 	X = unit(GID,_,_,_), | ||
|  | 	( memberchk(GID,GIDs) -> | ||
|  | 		L = [Unit,X|Xs] | ||
|  | 	; | ||
|  | 		L = [X | T], | ||
|  | 		dependency_insert(Xs,Unit,GIDs,T) | ||
|  | 	). | ||
|  | 
 | ||
|  | build_units(Retrievals,Guard,InitialDict,Units) :- | ||
|  | 	build_retrieval_units(Retrievals,1,N,InitialDict,Dict,Units,Tail), | ||
|  | 	build_guard_units(Guard,N,Dict,Tail). | ||
|  | 
 | ||
|  | build_retrieval_units([],N,N,Dict,Dict,L,L). | ||
|  | build_retrieval_units([U|Us],N,M,Dict,NDict,L,T) :- | ||
|  | 	term_variables(U,Vs), | ||
|  | 	update_unit_dictionary(Vs,N,Dict,Dict1,[],GIDs), | ||
|  | 	L = [unit(N,U,movable,GIDs)|L1], | ||
|  | 	N1 is N + 1, | ||
|  | 	build_retrieval_units2(Us,N1,M,Dict1,NDict,L1,T). | ||
|  | 
 | ||
|  | build_retrieval_units2([],N,N,Dict,Dict,L,L). | ||
|  | build_retrieval_units2([U|Us],N,M,Dict,NDict,L,T) :- | ||
|  | 	term_variables(U,Vs), | ||
|  | 	update_unit_dictionary(Vs,N,Dict,Dict1,[],GIDs), | ||
|  | 	L = [unit(N,U,fixed,GIDs)|L1], | ||
|  | 	N1 is N + 1, | ||
|  | 	build_retrieval_units(Us,N1,M,Dict1,NDict,L1,T). | ||
|  | 
 | ||
|  | initialize_unit_dictionary(Term,Dict) :- | ||
|  | 	term_variables(Term,Vars), | ||
|  | 	pair_all_with(Vars,0,Dict). | ||
|  | 
 | ||
|  | update_unit_dictionary([],_,Dict,Dict,GIDs,GIDs). | ||
|  | update_unit_dictionary([V|Vs],This,Dict,NDict,GIDs,NGIDs) :- | ||
|  | 	( lookup_eq(Dict,V,GID) -> | ||
|  | 		( (GID == This ; memberchk(GID,GIDs) ) -> | ||
|  | 			GIDs1 = GIDs | ||
|  | 		; | ||
|  | 			GIDs1 = [GID|GIDs] | ||
|  | 		), | ||
|  | 		Dict1 = Dict | ||
|  | 	; | ||
|  | 		Dict1 = [V - This|Dict], | ||
|  | 		GIDs1 = GIDs | ||
|  | 	), | ||
|  | 	update_unit_dictionary(Vs,This,Dict1,NDict,GIDs1,NGIDs). | ||
|  | 
 | ||
|  | build_guard_units(Guard,N,Dict,Units) :- | ||
|  | 	( Guard = [Goal] -> | ||
|  | 		Units = [unit(N,Goal,fixed,[])] | ||
|  | 	; Guard = [Goal|Goals] -> | ||
|  | 		term_variables(Goal,Vs), | ||
|  | 		update_unit_dictionary2(Vs,N,Dict,NDict,[],GIDs), | ||
|  | 		Units = [unit(N,Goal,movable,GIDs)|RUnits], | ||
|  | 		N1 is N + 1, | ||
|  | 		build_guard_units(Goals,N1,NDict,RUnits) | ||
|  | 	). | ||
|  | 
 | ||
|  | update_unit_dictionary2([],_,Dict,Dict,GIDs,GIDs). | ||
|  | update_unit_dictionary2([V|Vs],This,Dict,NDict,GIDs,NGIDs) :- | ||
|  | 	( lookup_eq(Dict,V,GID) -> | ||
|  | 		( (GID == This ; memberchk(GID,GIDs) ) -> | ||
|  | 			GIDs1 = GIDs | ||
|  | 		; | ||
|  | 			GIDs1 = [GID|GIDs] | ||
|  | 		), | ||
|  | 		Dict1 = [V - This|Dict] | ||
|  | 	; | ||
|  | 		Dict1 = [V - This|Dict], | ||
|  | 		GIDs1 = GIDs | ||
|  | 	), | ||
|  | 	update_unit_dictionary2(Vs,This,Dict1,NDict,GIDs1,NGIDs). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %%  ____       _     ____                             _   _ | ||
|  | %% / ___|  ___| |_  / ___|  ___ _ __ ___   __ _ _ __ | |_(_) ___ ___ _ | ||
|  | %% \___ \ / _ \ __| \___ \ / _ \ '_ ` _ \ / _` | '_ \| __| |/ __/ __(_) | ||
|  | %%  ___) |  __/ |_   ___) |  __/ | | | | | (_| | | | | |_| | (__\__ \_ | ||
|  | %% |____/ \___|\__| |____/ \___|_| |_| |_|\__,_|_| |_|\__|_|\___|___(_) | ||
|  | %% | ||
|  | %%  _   _       _                    ___        __ | ||
|  | %% | | | |_ __ (_) __ _ _   _  ___  |_ _|_ __  / _| ___ _ __ ___ _ __   ___ ___ | ||
|  | %% | | | | '_ \| |/ _` | | | |/ _ \  | || '_ \| |_ / _ \ '__/ _ \ '_ \ / __/ _ \ | ||
|  | %% | |_| | | | | | (_| | |_| |  __/  | || | | |  _|  __/ | |  __/ | | | (_|  __/ | ||
|  | %%  \___/|_| |_|_|\__, |\__,_|\___| |___|_| |_|_|  \___|_|  \___|_| |_|\___\___| | ||
|  | %%                   |_| | ||
|  | unique_analyse_optimise(Rules,NRules) :- | ||
|  | 		( chr_pp_flag(unique_analyse_optimise,on) -> | ||
|  | 			unique_analyse_optimise_main(Rules,1,[],NRules) | ||
|  | 		; | ||
|  | 			NRules = Rules | ||
|  | 		). | ||
|  | 
 | ||
|  | unique_analyse_optimise_main([],_,_,[]). | ||
|  | unique_analyse_optimise_main([PRule|PRules],N,PatternList,[NPRule|NPRules]) :- | ||
|  | 	( discover_unique_pattern(PRule,N,Pattern) -> | ||
|  | 		NPatternList = [Pattern|PatternList] | ||
|  | 	; | ||
|  | 		NPatternList = PatternList | ||
|  | 	), | ||
|  | 	PRule = pragma(Rule,Ids,Pragmas,Name,RuleNb), | ||
|  | 	Rule = rule(H1,H2,_,_), | ||
|  | 	Ids = ids(Ids1,Ids2), | ||
|  | 	apply_unique_patterns_to_constraints(H1,Ids1,NPatternList,MorePragmas1), | ||
|  | 	apply_unique_patterns_to_constraints(H2,Ids2,NPatternList,MorePragmas2), | ||
|  | 	globalize_unique_pragmas(MorePragmas1,RuleNb), | ||
|  | 	globalize_unique_pragmas(MorePragmas2,RuleNb), | ||
|  | 	append([MorePragmas1,MorePragmas2,Pragmas],NPragmas), | ||
|  | 	NPRule = pragma(Rule,Ids,NPragmas,Name,RuleNb), | ||
|  | 	N1 is N + 1, | ||
|  | 	unique_analyse_optimise_main(PRules,N1,NPatternList,NPRules). | ||
|  | 
 | ||
|  | globalize_unique_pragmas([],_). | ||
|  | globalize_unique_pragmas([unique(ID,Vars)|R],RuleNb) :- | ||
|  | 	pragma_unique(RuleNb,ID,Vars), | ||
|  | 	globalize_unique_pragmas(R,RuleNb). | ||
|  | 
 | ||
|  | apply_unique_patterns_to_constraints([],_,_,[]). | ||
|  | apply_unique_patterns_to_constraints([C|Cs],[Id|Ids],Patterns,Pragmas) :- | ||
|  | 	( member(Pattern,Patterns), | ||
|  | 	  apply_unique_pattern(C,Id,Pattern,Pragma) -> | ||
|  | 		Pragmas = [Pragma | RPragmas] | ||
|  | 	; | ||
|  | 		Pragmas = RPragmas | ||
|  | 	), | ||
|  | 	apply_unique_patterns_to_constraints(Cs,Ids,Patterns,RPragmas). | ||
|  | 
 | ||
|  | apply_unique_pattern(Constraint,Id,Pattern,Pragma) :- | ||
|  | 	Pattern = unique(PatternConstraint,PatternKey), | ||
|  | 	subsumes(Constraint,PatternConstraint,Unifier), | ||
|  | 	find_with_var_identity(	V, | ||
|  | 			Unifier | ||
|  | 			, | ||
|  | 			( | ||
|  | 				member(T,PatternKey), | ||
|  | 				lookup_eq(Unifier,T,Term), | ||
|  | 				term_variables(Term,Vs), | ||
|  | 				member(V,Vs) | ||
|  | 			), | ||
|  | 			Vars2), | ||
|  | 	sort(Vars2,Vars3), | ||
|  | 	Vars = Vars3, | ||
|  | 	Pragma = unique(Id,Vars). | ||
|  | 
 | ||
|  | %	subsumes(+Term1, +Term2, -Unifier) | ||
|  | % | ||
|  | %	If Term1 is a more general term   than  Term2 (e.g. has a larger | ||
|  | %	part instantiated), unify  Unifier  with   a  list  Var-Value of | ||
|  | %	variables from Term2 and their corresponding values in Term1. | ||
|  | 
 | ||
|  | subsumes(Term1,Term2,Unifier) :- | ||
|  | 	empty_ds(S0), | ||
|  | 	subsumes_aux(Term1,Term2,S0,S), | ||
|  | 	ds_to_list(S,L), | ||
|  | 	build_unifier(L,Unifier). | ||
|  | 
 | ||
|  | subsumes_aux(Term1, Term2, S0, S) :- | ||
|  |         (   compound(Term2), | ||
|  |             functor(Term2, F, N) | ||
|  |         ->  compound(Term1), functor(Term1, F, N), | ||
|  |             subsumes_aux(N, Term1, Term2, S0, S) | ||
|  |         ;   Term1 == Term2 | ||
|  | 	->  S = S0 | ||
|  | 	;   var(Term2), | ||
|  | 	    get_ds(Term1,S0,V) | ||
|  | 	->  V == Term2, S = S0 | ||
|  | 	;   var(Term2), | ||
|  | 	    put_ds(Term1, S0, Term2, S) | ||
|  |         ). | ||
|  | 
 | ||
|  | subsumes_aux(0, _, _, S, S) :- ! . | ||
|  | subsumes_aux(N, T1, T2, S0, S) :- | ||
|  |         arg(N, T1, T1x), | ||
|  |         arg(N, T2, T2x), | ||
|  |         subsumes_aux(T1x, T2x, S0, S1), | ||
|  |         M is N-1, | ||
|  |         subsumes_aux(M, T1, T2, S1, S). | ||
|  | 
 | ||
|  | build_unifier([],[]). | ||
|  | build_unifier([X-V|R],[V - X | T]) :- | ||
|  | 	build_unifier(R,T). | ||
|  | 
 | ||
|  | discover_unique_pattern(PragmaRule,RuleNb,Pattern) :- | ||
|  | 	PragmaRule = pragma(Rule,_,_Pragmas,Name,RuleNb), | ||
|  | 	Rule = rule(H1,H2,Guard,_), | ||
|  | 	( H1 = [C1], | ||
|  | 	  H2 = [C2] -> | ||
|  | 		true | ||
|  | 	; H1 = [C1,C2], | ||
|  | 	  H2 == [] -> | ||
|  | 		true | ||
|  | 	), | ||
|  | 	check_unique_constraints(C1,C2,Guard,RuleNb,List), | ||
|  | 	term_variables(C1,Vs), | ||
|  | 	select_pragma_unique_variables(List,Vs,Key), | ||
|  | 	Pattern0 = unique(C1,Key), | ||
|  | 	copy_term_nat(Pattern0,Pattern), | ||
|  | 	( verbosity_on -> | ||
|  | 		format('Found unique pattern ~w in rule ~d~@\n', | ||
|  | 			[Pattern,RuleNb,(Name=yes(N) -> write(": "),write(N) ; true)]) | ||
|  | 	; | ||
|  | 		true | ||
|  | 	). | ||
|  | 
 | ||
|  | select_pragma_unique_variables([],_,[]). | ||
|  | select_pragma_unique_variables([X-Y|R],Vs,L) :- | ||
|  | 	( X == Y -> | ||
|  | 		L = [X|T] | ||
|  | 	; | ||
|  | 		once(( | ||
|  | 			\+ memberchk_eq(X,Vs) | ||
|  | 		; | ||
|  | 			\+ memberchk_eq(Y,Vs) | ||
|  | 		)), | ||
|  | 		L = T | ||
|  | 	), | ||
|  | 	select_pragma_unique_variables(R,Vs,T). | ||
|  | 
 | ||
|  | check_unique_constraints(C1,C2,G,RuleNb,List) :- | ||
|  | 	\+ any_passive_head(RuleNb), | ||
|  | 	variable_replacement(C1-C2,C2-C1,List), | ||
|  | 	copy_with_variable_replacement(G,OtherG,List), | ||
|  | 	negate_b(G,NotG), | ||
|  | 	once(entails_b(NotG,OtherG)). | ||
|  | 
 | ||
|  | check_unnecessary_active(Constraint,Previous,Rule) :- | ||
|  | 	( chr_pp_flag(check_unnecessary_active,full) -> | ||
|  | 		check_unnecessary_active_main(Constraint,Previous,Rule) | ||
|  | 	; chr_pp_flag(check_unnecessary_active,simplification), | ||
|  | 	  Rule = rule(_,[],_,_) -> | ||
|  | 		check_unnecessary_active_main(Constraint,Previous,Rule) | ||
|  | 	; | ||
|  | 		fail | ||
|  | 	). | ||
|  | 
 | ||
|  | check_unnecessary_active_main(Constraint,Previous,Rule) :- | ||
|  |    member(Other,Previous), | ||
|  |    variable_replacement(Other,Constraint,List), | ||
|  |    copy_with_variable_replacement(Rule,Rule2,List), | ||
|  |    identical_rules(Rule,Rule2), ! . | ||
|  | 
 | ||
|  | set_semantics_rule(PragmaRule) :- | ||
|  | 	( chr_pp_flag(set_semantics_rule,on) -> | ||
|  | 		set_semantics_rule_main(PragmaRule) | ||
|  | 	; | ||
|  | 		fail | ||
|  | 	). | ||
|  | 
 | ||
|  | set_semantics_rule_main(PragmaRule) :- | ||
|  | 	PragmaRule = pragma(Rule,IDs,Pragmas,_,RuleNb), | ||
|  | 	Rule = rule([C1],[C2],true,_), | ||
|  | 	IDs = ids([ID1],[ID2]), | ||
|  | 	once(member(unique(ID1,L1),Pragmas)), | ||
|  | 	once(member(unique(ID2,L2),Pragmas)), | ||
|  | 	L1 == L2, | ||
|  | 	\+ is_passive(RuleNb,ID1). | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %%  ____        _        _____            _            _ | ||
|  | %% |  _ \ _   _| | ___  | ____|__ _ _   _(_)_   ____ _| | ___ _ __   ___ ___ | ||
|  | %% | |_) | | | | |/ _ \ |  _| / _` | | | | \ \ / / _` | |/ _ \ '_ \ / __/ _ \ | ||
|  | %% |  _ <| |_| | |  __/ | |__| (_| | |_| | |\ V / (_| | |  __/ | | | (_|  __/ | ||
|  | %% |_| \_\\__,_|_|\___| |_____\__, |\__,_|_| \_/ \__,_|_|\___|_| |_|\___\___| | ||
|  | %%                               |_| | ||
|  | % have to check for no duplicates in value list | ||
|  | 
 | ||
|  | % check wether two rules are identical | ||
|  | 
 | ||
|  | identical_rules(rule(H11,H21,G1,B1),rule(H12,H22,G2,B2)) :- | ||
|  |    G1 == G2, | ||
|  |    identical_bodies(B1,B2), | ||
|  |    permutation(H11,P1), | ||
|  |    P1 == H12, | ||
|  |    permutation(H21,P2), | ||
|  |    P2 == H22. | ||
|  | 
 | ||
|  | identical_bodies(B1,B2) :- | ||
|  |    ( B1 = (X1 = Y1), | ||
|  |      B2 = (X2 = Y2) -> | ||
|  |      ( X1 == X2, | ||
|  |        Y1 == Y2 | ||
|  |      ; X1 == Y2, | ||
|  |        X2 == Y1 | ||
|  |      ), | ||
|  |      ! | ||
|  |    ; B1 == B2 | ||
|  |    ). | ||
|  | 
 | ||
|  | % replace variables in list | ||
|  | 
 | ||
|  | copy_with_variable_replacement(X,Y,L) :- | ||
|  |    ( var(X) -> | ||
|  |      ( lookup_eq(L,X,Y) -> | ||
|  |        true | ||
|  |      ; X = Y | ||
|  |      ) | ||
|  |    ; functor(X,F,A), | ||
|  |      functor(Y,F,A), | ||
|  |      X =.. [_|XArgs], | ||
|  |      Y =.. [_|YArgs], | ||
|  |      copy_with_variable_replacement_l(XArgs,YArgs,L) | ||
|  |    ). | ||
|  | 
 | ||
|  | copy_with_variable_replacement_l([],[],_). | ||
|  | copy_with_variable_replacement_l([X|Xs],[Y|Ys],L) :- | ||
|  |    copy_with_variable_replacement(X,Y,L), | ||
|  |    copy_with_variable_replacement_l(Xs,Ys,L). | ||
|  | 
 | ||
|  | %% build variable replacement list | ||
|  | 
 | ||
|  | variable_replacement(X,Y,L) :- | ||
|  |    variable_replacement(X,Y,[],L). | ||
|  | 
 | ||
|  | variable_replacement(X,Y,L1,L2) :- | ||
|  |    ( var(X) -> | ||
|  |      var(Y), | ||
|  |      ( lookup_eq(L1,X,Z) -> | ||
|  |        Z == Y, | ||
|  |        L2 = L1 | ||
|  |      ; L2 = [X-Y|L1] | ||
|  |      ) | ||
|  |    ; X =.. [F|XArgs], | ||
|  |      nonvar(Y), | ||
|  |      Y =.. [F|YArgs], | ||
|  |      variable_replacement_l(XArgs,YArgs,L1,L2) | ||
|  |    ). | ||
|  | 
 | ||
|  | variable_replacement_l([],[],L,L). | ||
|  | variable_replacement_l([X|Xs],[Y|Ys],L1,L3) :- | ||
|  |    variable_replacement(X,Y,L1,L2), | ||
|  |    variable_replacement_l(Xs,Ys,L2,L3). | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %%  ____  _                 _ _  __ _           _   _ | ||
|  | %% / ___|(_)_ __ ___  _ __ | (_)/ _(_) ___ __ _| |_(_) ___  _ __ | ||
|  | %% \___ \| | '_ ` _ \| '_ \| | | |_| |/ __/ _` | __| |/ _ \| '_ \ | ||
|  | %%  ___) | | | | | | | |_) | | |  _| | (_| (_| | |_| | (_) | | | | | ||
|  | %% |____/|_|_| |_| |_| .__/|_|_|_| |_|\___\__,_|\__|_|\___/|_| |_| | ||
|  | %%                   |_| | ||
|  | 
 | ||
|  | simplification_code(Head,RestHeads,RestIDs,PragmaRule,F/A,Id,L,T) :- | ||
|  | 	PragmaRule = pragma(Rule,_,Pragmas,_,_RuleNb), | ||
|  | 	head_info(Head,A,_Vars,Susp,HeadVars,HeadPairs), | ||
|  | 	build_head(F,A,Id,HeadVars,ClauseHead), | ||
|  | 	head_arg_matches(HeadPairs,[],FirstMatching,VarDict1), | ||
|  | 
 | ||
|  | 	(   RestHeads == [] -> | ||
|  | 	    Susps = [], | ||
|  | 	    VarDict = VarDict1, | ||
|  | 	    GetRestHeads = [] | ||
|  | 	; | ||
|  | 	    rest_heads_retrieval_and_matching(RestHeads,RestIDs,Pragmas,Head,GetRestHeads,Susps,VarDict1,VarDict) | ||
|  | 	), | ||
|  | 
 | ||
|  | 	guard_body_copies2(Rule,VarDict,GuardCopyList,BodyCopy), | ||
|  | 	guard_via_reschedule(GetRestHeads,GuardCopyList,ClauseHead-FirstMatching,RescheduledTest), | ||
|  | 
 | ||
|  | 	gen_uncond_susps_detachments(Susps,RestHeads,SuspsDetachments), | ||
|  | 	gen_cond_susp_detachment(Id,Susp,F/A,SuspDetachment), | ||
|  | 
 | ||
|  | 	( chr_pp_flag(debugable,on) -> | ||
|  | 		Rule = rule(_,_,Guard,Body), | ||
|  | 		my_term_copy(Guard - Body, VarDict, _, DebugGuard - DebugBody), | ||
|  | 		DebugTry   = 'chr debug_event'(  try([Susp|RestSusps],[],DebugGuard,DebugBody)), | ||
|  | 		DebugApply = 'chr debug_event'(apply([Susp|RestSusps],[],DebugGuard,DebugBody)) | ||
|  | 	; | ||
|  | 		DebugTry = true, | ||
|  | 		DebugApply = true | ||
|  | 	), | ||
|  | 
 | ||
|  | 	Clause = ( ClauseHead :- | ||
|  | 		FirstMatching, | ||
|  | 		     RescheduledTest, | ||
|  | 		     DebugTry, | ||
|  | 	             !, | ||
|  | 		     DebugApply, | ||
|  | 	             SuspsDetachments, | ||
|  | 	             SuspDetachment, | ||
|  | 	             BodyCopy | ||
|  | 	         ), | ||
|  | 	L = [Clause | T]. | ||
|  | 
 | ||
|  | head_arg_matches(Pairs,VarDict,Goal,NVarDict) :- | ||
|  | 	head_arg_matches_(Pairs,VarDict,GoalList,NVarDict), | ||
|  | 	list2conj(GoalList,Goal). | ||
|  | 
 | ||
|  | head_arg_matches_([],VarDict,[],VarDict). | ||
|  | head_arg_matches_([Arg-Var| Rest],VarDict,GoalList,NVarDict) :- | ||
|  |    (   var(Arg) -> | ||
|  |        (   lookup_eq(VarDict,Arg,OtherVar) -> | ||
|  |            GoalList = [Var == OtherVar | RestGoalList], | ||
|  |            VarDict1 = VarDict | ||
|  |        ;   VarDict1 = [Arg-Var | VarDict], | ||
|  |            GoalList = RestGoalList | ||
|  |        ), | ||
|  |        Pairs = Rest | ||
|  |    ;   atomic(Arg) -> | ||
|  |        GoalList = [ Var == Arg | RestGoalList], | ||
|  |        VarDict = VarDict1, | ||
|  |        Pairs = Rest | ||
|  |    ;   Arg =.. [_|Args], | ||
|  |        functor(Arg,Fct,N), | ||
|  |        functor(Term,Fct,N), | ||
|  |        Term =.. [_|Vars], | ||
|  |        GoalList =[ nonvar(Var), Var = Term | RestGoalList ], | ||
|  |        pairup(Args,Vars,NewPairs), | ||
|  |        append(NewPairs,Rest,Pairs), | ||
|  |        VarDict1 = VarDict | ||
|  |    ), | ||
|  |    head_arg_matches_(Pairs,VarDict1,RestGoalList,NVarDict). | ||
|  | 
 | ||
|  | rest_heads_retrieval_and_matching(Heads,IDs,Pragmas,ActiveHead,GoalList,Susps,VarDict,NVarDict):- | ||
|  | 	rest_heads_retrieval_and_matching(Heads,IDs,Pragmas,ActiveHead,GoalList,Susps,VarDict,NVarDict,[],[],[]). | ||
|  | 
 | ||
|  | rest_heads_retrieval_and_matching(Heads,IDs,Pragmas,ActiveHead,GoalList,Susps,VarDict,NVarDict,PrevHs,PrevSusps,AttrDict) :- | ||
|  | 	( Heads = [_|_] -> | ||
|  | 		rest_heads_retrieval_and_matching_n(Heads,IDs,Pragmas,PrevHs,PrevSusps,ActiveHead,GoalList,Susps,VarDict,NVarDict,AttrDict) | ||
|  | 	; | ||
|  | 		GoalList = [], | ||
|  | 		Susps = [], | ||
|  | 		VarDict = NVarDict | ||
|  | 	). | ||
|  | 
 | ||
|  | rest_heads_retrieval_and_matching_n([],_,_,_,_,_,[],[],VarDict,VarDict,AttrDict) :- | ||
|  | 	instantiate_pattern_goals(AttrDict). | ||
|  | rest_heads_retrieval_and_matching_n([H|Hs],[ID|IDs],Pragmas,PrevHs,PrevSusps,ActiveHead,[ViaGoal,Goal|Goals],[Susp|Susps],VarDict,NVarDict,AttrDict) :- | ||
|  | 	functor(H,F,A), | ||
|  | 	get_store_type(F/A,StoreType), | ||
|  | 	( StoreType == default -> | ||
|  | 		passive_head_via(H,[ActiveHead|PrevHs],AttrDict,VarDict,ViaGoal,Attr,NewAttrDict), | ||
|  | 		get_max_constraint_index(N), | ||
|  | 		( N == 1 -> | ||
|  | 			VarSusps = Attr | ||
|  | 		; | ||
|  | 			get_constraint_index(F/A,Pos), | ||
|  | 			make_attr(N,_Mask,SuspsList,Attr), | ||
|  | 			nth1(Pos,SuspsList,VarSusps) | ||
|  | 		) | ||
|  | 	; | ||
|  | 		lookup_passive_head(StoreType,H,[ActiveHead|PrevHs],VarDict,ViaGoal,VarSusps), | ||
|  | 		NewAttrDict = AttrDict | ||
|  | 	), | ||
|  | 	head_info(H,A,Vars,_,_,Pairs), | ||
|  | 	head_arg_matches(Pairs,VarDict,MatchingGoal,VarDict1), | ||
|  | 	Suspension =.. [suspension,_,State,_,_,_,_|Vars], | ||
|  | 	different_from_other_susps(H,Susp,PrevHs,PrevSusps,DiffSuspGoals), | ||
|  | 	create_get_mutable_ref(active,State,GetMutable), | ||
|  | 	Goal1 = | ||
|  | 	( | ||
|  | 		'chr sbag_member'(Susp,VarSusps), | ||
|  | 		Susp = Suspension, | ||
|  | 		GetMutable, | ||
|  | 		DiffSuspGoals, | ||
|  | 		MatchingGoal | ||
|  | 	), | ||
|  | 	( member(unique(ID,UniqueKeus),Pragmas), | ||
|  | 	  check_unique_keys(UniqueKeus,VarDict) -> | ||
|  | 		Goal = (Goal1 -> true) | ||
|  | 	; | ||
|  | 		Goal = Goal1 | ||
|  | 	), | ||
|  | 	rest_heads_retrieval_and_matching_n(Hs,IDs,Pragmas,[H|PrevHs],[Susp|PrevSusps],ActiveHead,Goals,Susps,VarDict1,NVarDict,NewAttrDict). | ||
|  | 
 | ||
|  | instantiate_pattern_goals([]). | ||
|  | instantiate_pattern_goals([_-attr(Attr,Bits,Goal)|Rest]) :- | ||
|  | 	get_max_constraint_index(N), | ||
|  | 	( N == 1 -> | ||
|  | 		Goal = true | ||
|  | 	; | ||
|  | 		make_attr(N,Mask,_,Attr), | ||
|  | 		or_list(Bits,Pattern), !, | ||
|  | 		Goal = (Mask /\ Pattern =:= Pattern) | ||
|  | 	), | ||
|  | 	instantiate_pattern_goals(Rest). | ||
|  | 
 | ||
|  | 
 | ||
|  | check_unique_keys([],_). | ||
|  | check_unique_keys([V|Vs],Dict) :- | ||
|  | 	lookup_eq(Dict,V,_), | ||
|  | 	check_unique_keys(Vs,Dict). | ||
|  | 
 | ||
|  | % Generates tests to ensure the found constraint differs from previously found constraints | ||
|  | %	TODO: detect more cases where constraints need be different | ||
|  | different_from_other_susps(Head,Susp,Heads,Susps,DiffSuspGoals) :- | ||
|  | 	( bagof(DiffSuspGoal, Pos ^ ( nth1(Pos,Heads,PreHead), \+ Head \= PreHead, nth1(Pos,Susps,PreSusp), DiffSuspGoal = (Susp \== PreSusp) ),DiffSuspGoalList) -> | ||
|  | 	     list2conj(DiffSuspGoalList,DiffSuspGoals) | ||
|  | 	; | ||
|  | 	     DiffSuspGoals = true | ||
|  | 	). | ||
|  | 
 | ||
|  | passive_head_via(Head,PrevHeads,AttrDict,VarDict,Goal,Attr,NewAttrDict) :- | ||
|  | 	functor(Head,F,A), | ||
|  | 	get_constraint_index(F/A,Pos), | ||
|  | 	common_variables(Head,PrevHeads,CommonVars), | ||
|  | 	translate(CommonVars,VarDict,Vars), | ||
|  | 	or_pattern(Pos,Bit), | ||
|  | 	( permutation(Vars,PermutedVars), | ||
|  | 	  lookup_eq(AttrDict,PermutedVars,attr(Attr,Positions,_)) -> | ||
|  | 		member(Bit,Positions), !, | ||
|  | 		NewAttrDict = AttrDict, | ||
|  | 		Goal = true | ||
|  | 	; | ||
|  | 		Goal = (Goal1, PatternGoal), | ||
|  | 		gen_get_mod_constraints(Vars,Goal1,Attr), | ||
|  | 		NewAttrDict = [Vars - attr(Attr,[Bit|_],PatternGoal) | AttrDict] | ||
|  | 	). | ||
|  | 
 | ||
|  | common_variables(T,Ts,Vs) :- | ||
|  | 	term_variables(T,V1), | ||
|  | 	term_variables(Ts,V2), | ||
|  | 	intersect_eq(V1,V2,Vs). | ||
|  | 
 | ||
|  | gen_get_mod_constraints(L,Goal,Susps) :- | ||
|  |    get_target_module(Mod), | ||
|  |    (   L == [] -> | ||
|  |        Goal = | ||
|  |        (   'chr default_store'(Global), | ||
|  |            get_attr(Global,Mod,TSusps), | ||
|  | 	   TSusps = Susps | ||
|  |        ) | ||
|  |    ; | ||
|  |        (    L = [A] -> | ||
|  |             VIA =  'chr via_1'(A,V) | ||
|  |        ;    (   L = [A,B] -> | ||
|  |                 VIA = 'chr via_2'(A,B,V) | ||
|  |             ;   VIA = 'chr via'(L,V) | ||
|  |             ) | ||
|  |        ), | ||
|  |        Goal = | ||
|  |        (   VIA, | ||
|  |            get_attr(V,Mod,TSusps), | ||
|  | 	   TSusps = Susps | ||
|  |        ) | ||
|  |    ). | ||
|  | 
 | ||
|  | guard_body_copies(Rule,VarDict,GuardCopy,BodyCopy) :- | ||
|  | 	guard_body_copies2(Rule,VarDict,GuardCopyList,BodyCopy), | ||
|  | 	list2conj(GuardCopyList,GuardCopy). | ||
|  | 
 | ||
|  | guard_body_copies2(Rule,VarDict,GuardCopyList,BodyCopy) :- | ||
|  | 	Rule = rule(_,_,Guard,Body), | ||
|  | 	conj2list(Guard,GuardList), | ||
|  | 	split_off_simple_guard(GuardList,VarDict,GuardPrefix,RestGuardList), | ||
|  | 	my_term_copy(GuardPrefix-RestGuardList,VarDict,VarDict2,GuardPrefixCopy-RestGuardListCopyCore), | ||
|  | 
 | ||
|  | 	append(GuardPrefixCopy,[RestGuardCopy],GuardCopyList), | ||
|  | 	term_variables(RestGuardList,GuardVars), | ||
|  | 	term_variables(RestGuardListCopyCore,GuardCopyVars), | ||
|  | 	( chr_pp_flag(guard_locks,on), | ||
|  | 	  find_with_var_identity(('chr lock'(Y)) - ('chr unlock'(Y)), | ||
|  | 		VarDict, | ||
|  |                 (member(X,GuardVars),		% X is a variable appearing in the original guard | ||
|  |                      lookup_eq(VarDict,X,Y),            % translate X into new variable | ||
|  |                      memberchk_eq(Y,GuardCopyVars)      % redundant check? or multiple entries for X possible? | ||
|  |                     ), | ||
|  |                 LocksUnlocks) | ||
|  | 
 | ||
|  |  -> | ||
|  | 		once(pairup(Locks,Unlocks,LocksUnlocks)) | ||
|  | 	; | ||
|  | 		Locks = [], | ||
|  | 		Unlocks = [] | ||
|  | 	), | ||
|  | 	list2conj(Locks,LockPhase), | ||
|  | 	list2conj(Unlocks,UnlockPhase), | ||
|  | 	list2conj(RestGuardListCopyCore,RestGuardCopyCore), | ||
|  | 	RestGuardCopy = (LockPhase,(RestGuardCopyCore,UnlockPhase)), | ||
|  | 	my_term_copy(Body,VarDict2,BodyCopy). | ||
|  | 
 | ||
|  | 
 | ||
|  | split_off_simple_guard([],_,[],[]). | ||
|  | split_off_simple_guard([G|Gs],VarDict,S,C) :- | ||
|  | 	( simple_guard(G,VarDict) -> | ||
|  | 		S = [G|Ss], | ||
|  | 		split_off_simple_guard(Gs,VarDict,Ss,C) | ||
|  | 	; | ||
|  | 		S = [], | ||
|  | 		C = [G|Gs] | ||
|  | 	). | ||
|  | 
 | ||
|  | % simple guard: cheap and benign (does not bind variables) | ||
|  | simple_guard(G,VarDict) :- | ||
|  | 	binds_b(G,Vars), | ||
|  | 	not(( member(V,Vars), | ||
|  | 	     lookup_eq(VarDict,V,_) | ||
|  | 	   )). | ||
|  | 
 | ||
|  | my_term_copy(X,Dict,Y) :- | ||
|  |    my_term_copy(X,Dict,_,Y). | ||
|  | 
 | ||
|  | my_term_copy(X,Dict1,Dict2,Y) :- | ||
|  |    (   var(X) -> | ||
|  |        (   lookup_eq(Dict1,X,Y) -> | ||
|  |            Dict2 = Dict1 | ||
|  |        ;   Dict2 = [X-Y|Dict1] | ||
|  |        ) | ||
|  |    ;   functor(X,XF,XA), | ||
|  |        functor(Y,XF,XA), | ||
|  |        X =.. [_|XArgs], | ||
|  |        Y =.. [_|YArgs], | ||
|  |        my_term_copy_list(XArgs,Dict1,Dict2,YArgs) | ||
|  |    ). | ||
|  | 
 | ||
|  | my_term_copy_list([],Dict,Dict,[]). | ||
|  | my_term_copy_list([X|Xs],Dict1,Dict3,[Y|Ys]) :- | ||
|  |    my_term_copy(X,Dict1,Dict2,Y), | ||
|  |    my_term_copy_list(Xs,Dict2,Dict3,Ys). | ||
|  | 
 | ||
|  | gen_cond_susp_detachment(Id,Susp,FA,SuspDetachment) :- | ||
|  | 	( is_attached(FA) -> | ||
|  | 		( Id == [0], \+ may_trigger(FA) -> | ||
|  | 			SuspDetachment = true | ||
|  | 		; | ||
|  | 			gen_uncond_susp_detachment(Susp,FA,UnCondSuspDetachment), | ||
|  | 			SuspDetachment = | ||
|  | 			(   var(Susp) -> | ||
|  | 			    true | ||
|  | 			;   UnCondSuspDetachment | ||
|  | 			) | ||
|  | 		) | ||
|  | 	; | ||
|  | 	        SuspDetachment = true | ||
|  | 	). | ||
|  | 
 | ||
|  | gen_uncond_susp_detachment(Susp,FA,SuspDetachment) :- | ||
|  |    ( is_attached(FA) -> | ||
|  | 	( may_trigger(FA) -> | ||
|  | 		make_name('detach_',FA,Fct), | ||
|  | 		Detach =.. [Fct,Vars,Susp] | ||
|  | 	; | ||
|  | 		Detach = true | ||
|  | 	), | ||
|  | 	( chr_pp_flag(debugable,on) -> | ||
|  | 		DebugEvent = 'chr debug_event'(remove(Susp)) | ||
|  | 	; | ||
|  | 		DebugEvent = true | ||
|  | 	), | ||
|  | 	generate_delete_constraint_call(FA,Susp,DeleteCall), | ||
|  | 	SuspDetachment = | ||
|  | 	( | ||
|  | 		DebugEvent, | ||
|  | 		remove_constraint_internal(Susp, Vars, Delete), | ||
|  | 		( Delete == yes -> | ||
|  | 			DeleteCall, | ||
|  | 			Detach | ||
|  | 		; | ||
|  | 			true | ||
|  | 		) | ||
|  | 	) | ||
|  |    ; | ||
|  | 	SuspDetachment = true | ||
|  |    ). | ||
|  | 
 | ||
|  | gen_uncond_susps_detachments([],[],true). | ||
|  | gen_uncond_susps_detachments([Susp|Susps],[Term|Terms],(SuspDetachment,SuspsDetachments)) :- | ||
|  |    functor(Term,F,A), | ||
|  |    gen_uncond_susp_detachment(Susp,F/A,SuspDetachment), | ||
|  |    gen_uncond_susps_detachments(Susps,Terms,SuspsDetachments). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %%  ____  _                                   _   _               _ | ||
|  | %% / ___|(_)_ __ ___  _ __   __ _  __ _  __ _| |_(_) ___  _ __   / | | ||
|  | %% \___ \| | '_ ` _ \| '_ \ / _` |/ _` |/ _` | __| |/ _ \| '_ \  | | | ||
|  | %%  ___) | | | | | | | |_) | (_| | (_| | (_| | |_| | (_) | | | | | | | ||
|  | %% |____/|_|_| |_| |_| .__/ \__,_|\__, |\__,_|\__|_|\___/|_| |_| |_| | ||
|  | %%                   |_|          |___/ | ||
|  | 
 | ||
|  | simpagation_head1_code(Head,RestHeads,OtherIDs,PragmaRule,F/A,Id,L,T) :- | ||
|  |    PragmaRule = pragma(Rule,ids(_,Heads2IDs),Pragmas,_Name,RuleNb), | ||
|  |    Rule = rule(_Heads,Heads2,Guard,Body), | ||
|  | 
 | ||
|  |    head_info(Head,A,_Vars,Susp,HeadVars,HeadPairs), | ||
|  |    head_arg_matches(HeadPairs,[],FirstMatching,VarDict1), | ||
|  | 
 | ||
|  |    build_head(F,A,Id,HeadVars,ClauseHead), | ||
|  | 
 | ||
|  |    append(RestHeads,Heads2,Heads), | ||
|  |    append(OtherIDs,Heads2IDs,IDs), | ||
|  |    reorder_heads(RuleNb,Head,Heads,IDs,NHeads,NIDs), | ||
|  |    rest_heads_retrieval_and_matching(NHeads,NIDs,Pragmas,Head,GetRestHeads,Susps,VarDict1,VarDict), | ||
|  |    split_by_ids(NIDs,Susps,OtherIDs,Susps1,Susps2), | ||
|  | 
 | ||
|  |    guard_body_copies2(Rule,VarDict,GuardCopyList,BodyCopy), | ||
|  |    guard_via_reschedule(GetRestHeads,GuardCopyList,ClauseHead-FirstMatching,RescheduledTest), | ||
|  | 
 | ||
|  |    gen_uncond_susps_detachments(Susps1,RestHeads,SuspsDetachments), | ||
|  |    gen_cond_susp_detachment(Id,Susp,F/A,SuspDetachment), | ||
|  | 
 | ||
|  | 	( chr_pp_flag(debugable,on) -> | ||
|  | 		my_term_copy(Guard - Body, VarDict, _, DebugGuard - DebugBody), | ||
|  | 		DebugTry   = 'chr debug_event'(  try([Susp|Susps1],Susps2,DebugGuard,DebugBody)), | ||
|  | 		DebugApply = 'chr debug_event'(apply([Susp|Susps1],Susps2,DebugGuard,DebugBody)) | ||
|  | 	; | ||
|  | 		DebugTry = true, | ||
|  | 		DebugApply = true | ||
|  | 	), | ||
|  | 
 | ||
|  |    Clause = ( ClauseHead :- | ||
|  | 		FirstMatching, | ||
|  | 		RescheduledTest, | ||
|  | 		DebugTry, | ||
|  |                 !, | ||
|  | 		DebugApply, | ||
|  |                 SuspsDetachments, | ||
|  |                 SuspDetachment, | ||
|  |                 BodyCopy | ||
|  |             ), | ||
|  |    L = [Clause | T]. | ||
|  | 
 | ||
|  | split_by_ids([],[],_,[],[]). | ||
|  | split_by_ids([I|Is],[S|Ss],I1s,S1s,S2s) :- | ||
|  | 	( memberchk_eq(I,I1s) -> | ||
|  | 		S1s = [S | R1s], | ||
|  | 		S2s = R2s | ||
|  | 	; | ||
|  | 		S1s = R1s, | ||
|  | 		S2s = [S | R2s] | ||
|  | 	), | ||
|  | 	split_by_ids(Is,Ss,I1s,R1s,R2s). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %%  ____  _                                   _   _               ____ | ||
|  | %% / ___|(_)_ __ ___  _ __   __ _  __ _  __ _| |_(_) ___  _ __   |___ \ | ||
|  | %% \___ \| | '_ ` _ \| '_ \ / _` |/ _` |/ _` | __| |/ _ \| '_ \    __) | | ||
|  | %%  ___) | | | | | | | |_) | (_| | (_| | (_| | |_| | (_) | | | |  / __/ | ||
|  | %% |____/|_|_| |_| |_| .__/ \__,_|\__, |\__,_|\__|_|\___/|_| |_| |_____| | ||
|  | %%                   |_|          |___/ | ||
|  | 
 | ||
|  | %% Genereate prelude + worker predicate | ||
|  | %% prelude calls worker | ||
|  | %% worker iterates over one type of removed constraints | ||
|  | simpagation_head2_code(Head2,RestHeads2,RestIDs,PragmaRule,FA,Id,L,T) :- | ||
|  |    PragmaRule = pragma(Rule,ids(IDs1,_),Pragmas,_Name,RuleNb), | ||
|  |    Rule = rule(Heads1,_,Guard,Body), | ||
|  |    reorder_heads(RuleNb,Head2,Heads1,IDs1,[Head1|RestHeads1],[ID1|RestIDs1]),		% Heads1 = [Head1|RestHeads1], | ||
|  | 										% IDs1 = [ID1|RestIDs1], | ||
|  |    simpagation_head2_prelude(Head2,Head1,[RestHeads2,Heads1,Guard,Body],FA,Id,L,L1), | ||
|  |    extend_id(Id,Id2), | ||
|  |    simpagation_head2_worker(Head2,Head1,ID1,RestHeads1,RestIDs1,RestHeads2,RestIDs,PragmaRule,FA,Id2,L1,T). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | simpagation_head2_prelude(Head,Head1,Rest,F/A,Id1,L,T) :- | ||
|  | 	head_info(Head,A,Vars,Susp,VarsSusp,HeadPairs), | ||
|  | 	build_head(F,A,Id1,VarsSusp,ClauseHead), | ||
|  | 	head_arg_matches(HeadPairs,[],FirstMatching,VarDict), | ||
|  | 
 | ||
|  | 	lookup_passive_head(Head1,[Head],VarDict,ModConstraintsGoal,AllSusps), | ||
|  | 
 | ||
|  | 	gen_allocation(Id1,Vars,Susp,F/A,VarsSusp,ConstraintAllocationGoal), | ||
|  | 
 | ||
|  | 	extend_id(Id1,DelegateId), | ||
|  | 	extra_active_delegate_variables(Head,Rest,VarDict,ExtraVars), | ||
|  | 	append([AllSusps|VarsSusp],ExtraVars,DelegateCallVars), | ||
|  | 	build_head(F,A,DelegateId,DelegateCallVars,Delegate), | ||
|  | 
 | ||
|  | 	PreludeClause = | ||
|  | 	   ( ClauseHead :- | ||
|  | 	          FirstMatching, | ||
|  | 	          ModConstraintsGoal, | ||
|  | 	          !, | ||
|  | 	          ConstraintAllocationGoal, | ||
|  | 	          Delegate | ||
|  | 	   ), | ||
|  | 	L = [PreludeClause|T]. | ||
|  | 
 | ||
|  | extra_active_delegate_variables(Term,Terms,VarDict,Vars) :- | ||
|  | 	Term =.. [_|Args], | ||
|  | 	delegate_variables(Term,Terms,VarDict,Args,Vars). | ||
|  | 
 | ||
|  | passive_delegate_variables(Term,PrevTerms,NextTerms,VarDict,Vars) :- | ||
|  | 	term_variables(PrevTerms,PrevVars), | ||
|  | 	delegate_variables(Term,NextTerms,VarDict,PrevVars,Vars). | ||
|  | 
 | ||
|  | delegate_variables(Term,Terms,VarDict,PrevVars,Vars) :- | ||
|  | 	term_variables(Term,V1), | ||
|  | 	term_variables(Terms,V2), | ||
|  | 	intersect_eq(V1,V2,V3), | ||
|  | 	list_difference_eq(V3,PrevVars,V4), | ||
|  | 	translate(V4,VarDict,Vars). | ||
|  | 
 | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | simpagation_head2_worker(Head2,Head1,ID1,RestHeads1,IDs1,RestHeads2,IDs2,PragmaRule,FA,Id,L,T) :- | ||
|  |    PragmaRule = pragma(Rule,_,_,_,_), | ||
|  |    Rule = rule(_,_,Guard,Body), | ||
|  |    simpagation_head2_worker_end(Head2,[Head1,RestHeads1,RestHeads2,Guard,Body],FA,Id,L,L1), | ||
|  |    simpagation_head2_worker_body(Head2,Head1,ID1,RestHeads1,IDs1,RestHeads2,IDs2,PragmaRule,FA,Id,L1,T). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | simpagation_head2_worker_body(Head2,Head1,ID1,RestHeads1,IDs1,RestHeads2,IDs2,PragmaRule,F/A,Id,L,T) :- | ||
|  |    gen_var(OtherSusp), | ||
|  |    gen_var(OtherSusps), | ||
|  | 
 | ||
|  |    head_info(Head2,A,_Vars,Susp,VarsSusp,Head2Pairs), | ||
|  |    head_arg_matches(Head2Pairs,[],_,VarDict1), | ||
|  | 
 | ||
|  |    PragmaRule = pragma(Rule,_,Pragmas,_,RuleNb), | ||
|  |    Rule = rule(_,_,Guard,Body), | ||
|  |    extra_active_delegate_variables(Head2,[Head1,RestHeads1,RestHeads2,Guard,Body],VarDict1,ExtraVars), | ||
|  |    append([[OtherSusp|OtherSusps]|VarsSusp],ExtraVars,HeadVars), | ||
|  |    build_head(F,A,Id,HeadVars,ClauseHead), | ||
|  | 
 | ||
|  |    functor(Head1,_OtherF,OtherA), | ||
|  |    head_info(Head1,OtherA,OtherVars,_,_,Head1Pairs), | ||
|  |    head_arg_matches(Head1Pairs,VarDict1,FirstMatching,VarDict2), | ||
|  | 
 | ||
|  |    OtherSuspension =.. [suspension,_,OtherState,_,_,_,_|OtherVars], | ||
|  |    create_get_mutable_ref(active,OtherState,GetMutable), | ||
|  |    IteratorSuspTest = | ||
|  |       (   OtherSusp = OtherSuspension, | ||
|  |           GetMutable | ||
|  |       ), | ||
|  | 
 | ||
|  |    (   (RestHeads1 \== [] ; RestHeads2 \== []) -> | ||
|  | 		append(RestHeads1,RestHeads2,RestHeads), | ||
|  | 		append(IDs1,IDs2,IDs), | ||
|  | 		reorder_heads(RuleNb,Head1-Head2,RestHeads,IDs,NRestHeads,NIDs), | ||
|  | 		rest_heads_retrieval_and_matching(NRestHeads,NIDs,Pragmas,[Head1,Head2],RestSuspsRetrieval,Susps,VarDict2,VarDict,[Head1],[OtherSusp],[]), | ||
|  | 		split_by_ids(NIDs,Susps,IDs1,Susps1,Susps2) | ||
|  |    ;   RestSuspsRetrieval = [], | ||
|  |        Susps1 = [], | ||
|  |        Susps2 = [], | ||
|  |        VarDict = VarDict2 | ||
|  |    ), | ||
|  | 
 | ||
|  |    gen_uncond_susps_detachments([OtherSusp | Susps1],[Head1|RestHeads1],Susps1Detachments), | ||
|  | 
 | ||
|  |    append([OtherSusps|VarsSusp],ExtraVars,RecursiveVars), | ||
|  |    build_head(F,A,Id,RecursiveVars,RecursiveCall), | ||
|  |    append([[]|VarsSusp],ExtraVars,RecursiveVars2), | ||
|  |    build_head(F,A,Id,RecursiveVars2,RecursiveCall2), | ||
|  | 
 | ||
|  |    guard_body_copies2(Rule,VarDict,GuardCopyList,BodyCopy), | ||
|  |    guard_via_reschedule(RestSuspsRetrieval,GuardCopyList,v(ClauseHead,IteratorSuspTest,FirstMatching),RescheduledTest), | ||
|  |    (   BodyCopy \== true -> | ||
|  |        gen_uncond_attach_goal(F/A,Susp,Attachment,Generation), | ||
|  |        gen_state_cond_call(Susp,A,RecursiveCall,Generation,ConditionalRecursiveCall), | ||
|  |        gen_state_cond_call(Susp,A,RecursiveCall2,Generation,ConditionalRecursiveCall2) | ||
|  |    ;   Attachment = true, | ||
|  |        ConditionalRecursiveCall = RecursiveCall, | ||
|  |        ConditionalRecursiveCall2 = RecursiveCall2 | ||
|  |    ), | ||
|  | 
 | ||
|  | 	( chr_pp_flag(debugable,on) -> | ||
|  | 		my_term_copy(Guard - Body, VarDict, _, DebugGuard - DebugBody), | ||
|  | 		DebugTry   = 'chr debug_event'(  try([OtherSusp|Susps1],[Susp|Susps2],DebugGuard,DebugBody)), | ||
|  | 		DebugApply = 'chr debug_event'(apply([OtherSusp|Susps1],[Susp|Susps2],DebugGuard,DebugBody)) | ||
|  | 	; | ||
|  | 		DebugTry = true, | ||
|  | 		DebugApply = true | ||
|  | 	), | ||
|  | 
 | ||
|  |    ( member(unique(ID1,UniqueKeys), Pragmas), | ||
|  |      check_unique_keys(UniqueKeys,VarDict1) -> | ||
|  | 	Clause = | ||
|  | 		( ClauseHead :- | ||
|  | 			( IteratorSuspTest, | ||
|  | 			  FirstMatching -> | ||
|  | 				( RescheduledTest, | ||
|  | 				  DebugTry -> | ||
|  | 					DebugApply, | ||
|  | 					Susps1Detachments, | ||
|  | 					Attachment, | ||
|  | 					BodyCopy, | ||
|  | 					ConditionalRecursiveCall2 | ||
|  | 				; | ||
|  | 					RecursiveCall2 | ||
|  | 				) | ||
|  | 			; | ||
|  | 				RecursiveCall | ||
|  | 			) | ||
|  | 		) | ||
|  |     ; | ||
|  | 	Clause = | ||
|  | 		( ClauseHead :- | ||
|  | 			( IteratorSuspTest, | ||
|  | 			  FirstMatching, | ||
|  | 			  RescheduledTest, | ||
|  | 			  DebugTry -> | ||
|  | 				DebugApply, | ||
|  | 				Susps1Detachments, | ||
|  | 				Attachment, | ||
|  | 				BodyCopy, | ||
|  | 				ConditionalRecursiveCall | ||
|  | 			; | ||
|  | 				RecursiveCall | ||
|  | 			) | ||
|  | 		) | ||
|  |    ), | ||
|  |    L = [Clause | T]. | ||
|  | 
 | ||
|  | gen_state_cond_call(Susp,N,Call,Generation,ConditionalCall) :- | ||
|  |    length(Args,N), | ||
|  |    Suspension =.. [suspension,_,State,_,NewGeneration,_,_|Args], | ||
|  |    create_get_mutable_ref(active,State,GetState), | ||
|  |    create_get_mutable_ref(Generation,NewGeneration,GetGeneration), | ||
|  |    ConditionalCall = | ||
|  |       (   Susp = Suspension, | ||
|  | 	  GetState, | ||
|  |           GetGeneration -> | ||
|  | 		  'chr update_mutable'(inactive,State), | ||
|  | 	          Call | ||
|  | 	      ;   true | ||
|  |       ). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | simpagation_head2_worker_end(Head,Rest,F/A,Id,L,T) :- | ||
|  |    head_info(Head,A,_Vars,_Susp,VarsSusp,Pairs), | ||
|  |    head_arg_matches(Pairs,[],_,VarDict), | ||
|  |    extra_active_delegate_variables(Head,Rest,VarDict,ExtraVars), | ||
|  |    append([[]|VarsSusp],ExtraVars,HeadVars), | ||
|  |    build_head(F,A,Id,HeadVars,ClauseHead), | ||
|  |    next_id(Id,ContinuationId), | ||
|  |    build_head(F,A,ContinuationId,VarsSusp,ContinuationHead), | ||
|  |    Clause = ( ClauseHead :- ContinuationHead ), | ||
|  |    L = [Clause | T]. | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %%  ____                                    _   _ | ||
|  | %% |  _ \ _ __ ___  _ __   __ _  __ _  __ _| |_(_) ___  _ __ | ||
|  | %% | |_) | '__/ _ \| '_ \ / _` |/ _` |/ _` | __| |/ _ \| '_ \ | ||
|  | %% |  __/| | | (_) | |_) | (_| | (_| | (_| | |_| | (_) | | | | | ||
|  | %% |_|   |_|  \___/| .__/ \__,_|\__, |\__,_|\__|_|\___/|_| |_| | ||
|  | %%                 |_|          |___/ | ||
|  | 
 | ||
|  | propagation_code(Head,RestHeads,Rule,RuleNb,RestHeadNb,FA,Id,L,T) :- | ||
|  | 	( RestHeads == [] -> | ||
|  | 		propagation_single_headed(Head,Rule,RuleNb,FA,Id,L,T) | ||
|  | 	; | ||
|  | 		propagation_multi_headed(Head,RestHeads,Rule,RuleNb,RestHeadNb,FA,Id,L,T) | ||
|  | 	). | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %% Single headed propagation | ||
|  | %% everything in a single clause | ||
|  | propagation_single_headed(Head,Rule,RuleNb,F/A,Id,L,T) :- | ||
|  |    head_info(Head,A,Vars,Susp,VarsSusp,HeadPairs), | ||
|  |    build_head(F,A,Id,VarsSusp,ClauseHead), | ||
|  | 
 | ||
|  |    inc_id(Id,NextId), | ||
|  |    build_head(F,A,NextId,VarsSusp,NextHead), | ||
|  | 
 | ||
|  |    NextCall = NextHead, | ||
|  | 
 | ||
|  |    head_arg_matches(HeadPairs,[],HeadMatching,VarDict), | ||
|  |    guard_body_copies(Rule,VarDict,GuardCopy,BodyCopy), | ||
|  |    gen_allocation(Id,Vars,Susp,F/A,VarsSusp,Allocation), | ||
|  |    gen_uncond_attach_goal(F/A,Susp,Attachment,Generation), | ||
|  | 
 | ||
|  |    gen_state_cond_call(Susp,A,NextCall,Generation,ConditionalNextCall), | ||
|  | 
 | ||
|  | 	( chr_pp_flag(debugable,on) -> | ||
|  | 		Rule = rule(_,_,Guard,Body), | ||
|  | 		my_term_copy(Guard - Body, VarDict, _, DebugGuard - DebugBody), | ||
|  | 		DebugTry   = 'chr debug_event'(  try([],[Susp],DebugGuard,DebugBody)), | ||
|  | 		DebugApply = 'chr debug_event'(apply([],[Susp],DebugGuard,DebugBody)) | ||
|  | 	; | ||
|  | 		DebugTry = true, | ||
|  | 		DebugApply = true | ||
|  | 	), | ||
|  | 
 | ||
|  |    Clause = ( | ||
|  |         ClauseHead :- | ||
|  | 		HeadMatching, | ||
|  | 		Allocation, | ||
|  | 		'chr novel_production'(Susp,RuleNb),	% optimisation of t(RuleNb,Susp) | ||
|  | 		GuardCopy, | ||
|  | 		DebugTry, | ||
|  | 		!, | ||
|  | 		DebugApply, | ||
|  | 		'chr extend_history'(Susp,RuleNb), | ||
|  | 		Attachment, | ||
|  | 		BodyCopy, | ||
|  | 		ConditionalNextCall | ||
|  |    ), | ||
|  |    L = [Clause | T]. | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %% multi headed propagation | ||
|  | %% prelude + predicates to accumulate the necessary combinations of suspended | ||
|  | %% constraints + predicate to execute the body | ||
|  | propagation_multi_headed(Head,RestHeads,Rule,RuleNb,RestHeadNb,FA,Id,L,T) :- | ||
|  |    RestHeads = [First|Rest], | ||
|  |    propagation_prelude(Head,RestHeads,Rule,FA,Id,L,L1), | ||
|  |    extend_id(Id,ExtendedId), | ||
|  |    propagation_nested_code(Rest,[First,Head],Rule,RuleNb,RestHeadNb,FA,ExtendedId,L1,T). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | propagation_prelude(Head,[First|Rest],Rule,F/A,Id,L,T) :- | ||
|  |    head_info(Head,A,Vars,Susp,VarsSusp,HeadPairs), | ||
|  |    build_head(F,A,Id,VarsSusp,PreludeHead), | ||
|  |    head_arg_matches(HeadPairs,[],FirstMatching,VarDict), | ||
|  |    Rule = rule(_,_,Guard,Body), | ||
|  |    extra_active_delegate_variables(Head,[First,Rest,Guard,Body],VarDict,ExtraVars), | ||
|  | 
 | ||
|  |    lookup_passive_head(First,[Head],VarDict,FirstSuspGoal,Susps), | ||
|  | 
 | ||
|  |    gen_allocation(Id,Vars,Susp,F/A,VarsSusp,CondAllocation), | ||
|  | 
 | ||
|  |    extend_id(Id,NestedId), | ||
|  |    append([Susps|VarsSusp],ExtraVars,NestedVars), | ||
|  |    build_head(F,A,NestedId,NestedVars,NestedHead), | ||
|  |    NestedCall = NestedHead, | ||
|  | 
 | ||
|  |    Prelude = ( | ||
|  |       PreludeHead :- | ||
|  | 	  FirstMatching, | ||
|  | 	  FirstSuspGoal, | ||
|  |           !, | ||
|  |           CondAllocation, | ||
|  |           NestedCall | ||
|  |    ), | ||
|  |    L = [Prelude|T]. | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | propagation_nested_code([],[CurrentHead|PreHeads],Rule,RuleNb,RestHeadNb,FA,Id,L,T) :- | ||
|  |    propagation_end([CurrentHead|PreHeads],[],Rule,FA,Id,L,L1), | ||
|  |    propagation_body(CurrentHead,PreHeads,Rule,RuleNb,RestHeadNb,FA,Id,L1,T). | ||
|  | 
 | ||
|  | propagation_nested_code([Head|RestHeads],PreHeads,Rule,RuleNb,RestHeadNb,FA,Id,L,T) :- | ||
|  |    propagation_end(PreHeads,[Head|RestHeads],Rule,FA,Id,L,L1), | ||
|  |    propagation_accumulator([Head|RestHeads],PreHeads,Rule,FA,Id,L1,L2), | ||
|  |    inc_id(Id,IncId), | ||
|  |    propagation_nested_code(RestHeads,[Head|PreHeads],Rule,RuleNb,RestHeadNb,FA,IncId,L2,T). | ||
|  | 
 | ||
|  | propagation_body(CurrentHead,PreHeads,Rule,RuleNb,RestHeadNb,F/A,Id,L,T) :- | ||
|  |    Rule = rule(_,_,Guard,Body), | ||
|  |    get_prop_inner_loop_vars(PreHeads,[CurrentHead,Guard,Body],PreVarsAndSusps,VarDict1,Susp,RestSusps), | ||
|  |    gen_var(OtherSusp), | ||
|  |    gen_var(OtherSusps), | ||
|  |    functor(CurrentHead,_OtherF,OtherA), | ||
|  |    gen_vars(OtherA,OtherVars), | ||
|  |    Suspension =.. [suspension,_,State,_,_,_,_|OtherVars], | ||
|  |    create_get_mutable_ref(active,State,GetMutable), | ||
|  |    CurrentSuspTest = ( | ||
|  |       OtherSusp = Suspension, | ||
|  |       GetMutable | ||
|  |    ), | ||
|  |    ClauseVars = [[OtherSusp|OtherSusps]|PreVarsAndSusps], | ||
|  |    build_head(F,A,Id,ClauseVars,ClauseHead), | ||
|  |    RecursiveVars = [OtherSusps|PreVarsAndSusps], | ||
|  |    build_head(F,A,Id,RecursiveVars,RecursiveHead), | ||
|  |    RecursiveCall = RecursiveHead, | ||
|  |    CurrentHead =.. [_|OtherArgs], | ||
|  |    pairup(OtherArgs,OtherVars,OtherPairs), | ||
|  |    head_arg_matches(OtherPairs,VarDict1,Matching,VarDict), | ||
|  | 
 | ||
|  |    different_from_other_susps(CurrentHead,OtherSusp,PreHeads,RestSusps,DiffSuspGoals), | ||
|  | 
 | ||
|  |    guard_body_copies(Rule,VarDict,GuardCopy,BodyCopy), | ||
|  |    gen_uncond_attach_goal(F/A,Susp,Attach,Generation), | ||
|  |    gen_state_cond_call(Susp,A,RecursiveCall,Generation,ConditionalRecursiveCall), | ||
|  | 
 | ||
|  |    history_susps(RestHeadNb,[OtherSusp|RestSusps],Susp,[],HistorySusps), | ||
|  |    bagof('chr novel_production'(X,Y),( member(X,HistorySusps), Y = TupleVar) ,NovelProductionsList), | ||
|  |    list2conj(NovelProductionsList,NovelProductions), | ||
|  |    Tuple =.. [t,RuleNb|HistorySusps], | ||
|  | 
 | ||
|  | 	( chr_pp_flag(debugable,on) -> | ||
|  | 		Rule = rule(_,_,Guard,Body), | ||
|  | 		my_term_copy(Guard - Body, VarDict, _, DebugGuard - DebugBody), | ||
|  | 		DebugTry   = 'chr debug_event'(  try([],[Susp,OtherSusp|RestSusps],DebugGuard,DebugBody)), | ||
|  | 		DebugApply = 'chr debug_event'(apply([],[Susp,OtherSusp|RestSusps],DebugGuard,DebugBody)) | ||
|  | 	; | ||
|  | 		DebugTry = true, | ||
|  | 		DebugApply = true | ||
|  | 	), | ||
|  | 
 | ||
|  |    Clause = ( | ||
|  |       ClauseHead :- | ||
|  |          (   CurrentSuspTest, | ||
|  | 	     DiffSuspGoals, | ||
|  |              Matching, | ||
|  | 	     TupleVar = Tuple, | ||
|  | 	     NovelProductions, | ||
|  |              GuardCopy, | ||
|  | 	     DebugTry -> | ||
|  | 	     DebugApply, | ||
|  | 	     'chr extend_history'(Susp,TupleVar), | ||
|  |              Attach, | ||
|  |              BodyCopy, | ||
|  |              ConditionalRecursiveCall | ||
|  |          ;   RecursiveCall | ||
|  |          ) | ||
|  |    ), | ||
|  |    L = [Clause|T]. | ||
|  | 
 | ||
|  | history_susps(Count,OtherSusps,Susp,Acc,HistorySusps) :- | ||
|  | 	( Count == 0 -> | ||
|  | 		reverse(OtherSusps,ReversedSusps), | ||
|  | 		append(ReversedSusps,[Susp|Acc],HistorySusps) | ||
|  | 	; | ||
|  | 		OtherSusps = [OtherSusp|RestOtherSusps], | ||
|  | 		NCount is Count - 1, | ||
|  | 		history_susps(NCount,RestOtherSusps,Susp,[OtherSusp|Acc],HistorySusps) | ||
|  | 	). | ||
|  | 
 | ||
|  | get_prop_inner_loop_vars([Head],Terms,HeadVars,VarDict,Susp,[]) :- | ||
|  | 	!, | ||
|  | 	functor(Head,_F,A), | ||
|  | 	head_info(Head,A,_Vars,Susp,VarsSusp,Pairs), | ||
|  | 	head_arg_matches(Pairs,[],_,VarDict), | ||
|  | 	extra_active_delegate_variables(Head,Terms,VarDict,ExtraVars), | ||
|  | 	append(VarsSusp,ExtraVars,HeadVars). | ||
|  | get_prop_inner_loop_vars([Head|Heads],Terms,VarsSusps,NVarDict,MainSusp,[Susp|RestSusps]) :- | ||
|  | 	get_prop_inner_loop_vars(Heads,[Head|Terms],RestVarsSusp,VarDict,MainSusp,RestSusps), | ||
|  | 	functor(Head,_F,A), | ||
|  | 	gen_var(Susps), | ||
|  | 	head_info(Head,A,_Vars,Susp,_VarsSusp,Pairs), | ||
|  | 	head_arg_matches(Pairs,VarDict,_,NVarDict), | ||
|  | 	passive_delegate_variables(Head,Heads,Terms,NVarDict,HeadVars), | ||
|  | 	append(HeadVars,[Susp,Susps|RestVarsSusp],VarsSusps). | ||
|  | 
 | ||
|  | propagation_end([CurrentHead|PrevHeads],NextHeads,Rule,F/A,Id,L,T) :- | ||
|  |    Rule = rule(_,_,Guard,Body), | ||
|  |    gen_var_susp_list_for(PrevHeads,[CurrentHead,NextHeads,Guard,Body],_,VarsAndSusps,AllButFirst,FirstSusp), | ||
|  | 
 | ||
|  |    Vars = [ [] | VarsAndSusps], | ||
|  | 
 | ||
|  |    build_head(F,A,Id,Vars,Head), | ||
|  | 
 | ||
|  |    (   Id = [0|_] -> | ||
|  |        next_id(Id,PrevId), | ||
|  |        PrevVarsAndSusps = AllButFirst | ||
|  |    ; | ||
|  |        dec_id(Id,PrevId), | ||
|  |        PrevVarsAndSusps = [FirstSusp|AllButFirst] | ||
|  |    ), | ||
|  | 
 | ||
|  |    build_head(F,A,PrevId,PrevVarsAndSusps,PrevHead), | ||
|  |    PredecessorCall = PrevHead, | ||
|  | 
 | ||
|  |    Clause = ( | ||
|  |       Head :- | ||
|  |          PredecessorCall | ||
|  |    ), | ||
|  |    L = [Clause | T]. | ||
|  | 
 | ||
|  | gen_var_susp_list_for([Head],Terms,VarDict,HeadVars,VarsSusp,Susp) :- | ||
|  |    !, | ||
|  |    functor(Head,_F,A), | ||
|  |    head_info(Head,A,_Vars,Susp,VarsSusp,HeadPairs), | ||
|  |    head_arg_matches(HeadPairs,[],_,VarDict), | ||
|  |    extra_active_delegate_variables(Head,Terms,VarDict,ExtraVars), | ||
|  |    append(VarsSusp,ExtraVars,HeadVars). | ||
|  | gen_var_susp_list_for([Head|Heads],Terms,NVarDict,VarsSusps,Rest,Susps) :- | ||
|  | 	gen_var_susp_list_for(Heads,[Head|Terms],VarDict,Rest,_,_), | ||
|  | 	functor(Head,_F,A), | ||
|  | 	gen_var(Susps), | ||
|  | 	head_info(Head,A,_Vars,Susp,_VarsSusp,HeadPairs), | ||
|  | 	head_arg_matches(HeadPairs,VarDict,_,NVarDict), | ||
|  | 	passive_delegate_variables(Head,Heads,Terms,NVarDict,HeadVars), | ||
|  | 	append(HeadVars,[Susp,Susps|Rest],VarsSusps). | ||
|  | 
 | ||
|  | propagation_accumulator([NextHead|RestHeads],[CurrentHead|PreHeads],Rule,F/A,Id,L,T) :- | ||
|  | 	Rule = rule(_,_,Guard,Body), | ||
|  | 	pre_vars_and_susps(PreHeads,[CurrentHead,NextHead,RestHeads,Guard,Body],PreVarsAndSusps,VarDict,PreSusps), | ||
|  | 	gen_var(OtherSusps), | ||
|  | 	functor(CurrentHead,_OtherF,OtherA), | ||
|  | 	gen_vars(OtherA,OtherVars), | ||
|  | 	head_info(CurrentHead,OtherA,OtherVars,OtherSusp,_VarsSusp,HeadPairs), | ||
|  | 	head_arg_matches(HeadPairs,VarDict,FirstMatching,VarDict1), | ||
|  | 
 | ||
|  | 	OtherSuspension =.. [suspension,_,State,_,_,_,_|OtherVars], | ||
|  | 
 | ||
|  | 	different_from_other_susps(CurrentHead,OtherSusp,PreHeads,PreSusps,DiffSuspGoals), | ||
|  | 	create_get_mutable_ref(active,State,GetMutable), | ||
|  | 	CurrentSuspTest = ( | ||
|  | 	   OtherSusp = OtherSuspension, | ||
|  | 	   GetMutable, | ||
|  | 	   DiffSuspGoals, | ||
|  | 	   FirstMatching | ||
|  | 	), | ||
|  |         lookup_passive_head(NextHead,[CurrentHead|PreHeads],VarDict1,NextSuspGoal,NextSusps), | ||
|  | 	inc_id(Id,NestedId), | ||
|  | 	ClauseVars = [[OtherSusp|OtherSusps]|PreVarsAndSusps], | ||
|  | 	build_head(F,A,Id,ClauseVars,ClauseHead), | ||
|  | 	passive_delegate_variables(CurrentHead,PreHeads,[NextHead,RestHeads,Guard,Body],VarDict1,CurrentHeadVars), | ||
|  | 	append([NextSusps|CurrentHeadVars],[OtherSusp,OtherSusps|PreVarsAndSusps],NestedVars), | ||
|  | 	build_head(F,A,NestedId,NestedVars,NestedHead), | ||
|  | 
 | ||
|  | 	RecursiveVars = [OtherSusps|PreVarsAndSusps], | ||
|  | 	build_head(F,A,Id,RecursiveVars,RecursiveHead), | ||
|  | 	Clause = ( | ||
|  | 	   ClauseHead :- | ||
|  | 	   (   CurrentSuspTest, | ||
|  | 	       NextSuspGoal | ||
|  | 	       -> | ||
|  | 	       NestedHead | ||
|  | 	   ;   RecursiveHead | ||
|  | 	   ) | ||
|  | 	), | ||
|  | 	L = [Clause|T]. | ||
|  | 
 | ||
|  | pre_vars_and_susps([Head],Terms,HeadVars,VarDict,[]) :- | ||
|  | 	!, | ||
|  | 	functor(Head,_F,A), | ||
|  | 	head_info(Head,A,_Vars,_Susp,VarsSusp,HeadPairs), | ||
|  | 	head_arg_matches(HeadPairs,[],_,VarDict), | ||
|  | 	extra_active_delegate_variables(Head,Terms,VarDict,ExtraVars), | ||
|  | 	append(VarsSusp,ExtraVars,HeadVars). | ||
|  | pre_vars_and_susps([Head|Heads],Terms,NVSs,NVarDict,[Susp|Susps]) :- | ||
|  | 	pre_vars_and_susps(Heads,[Head|Terms],VSs,VarDict,Susps), | ||
|  | 	functor(Head,_F,A), | ||
|  | 	gen_var(NextSusps), | ||
|  | 	head_info(Head,A,_Vars,Susp,_VarsSusp,HeadPairs), | ||
|  | 	head_arg_matches(HeadPairs,VarDict,_,NVarDict), | ||
|  | 	passive_delegate_variables(Head,Heads,Terms,NVarDict,HeadVars), | ||
|  | 	append(HeadVars,[Susp,NextSusps|VSs],NVSs). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %%  ____               _             _   _                _ | ||
|  | %% |  _ \ __ _ ___ ___(_)_   _____  | | | | ___  __ _  __| | | ||
|  | %% | |_) / _` / __/ __| \ \ / / _ \ | |_| |/ _ \/ _` |/ _` | | ||
|  | %% |  __/ (_| \__ \__ \ |\ V /  __/ |  _  |  __/ (_| | (_| | | ||
|  | %% |_|   \__,_|___/___/_| \_/ \___| |_| |_|\___|\__,_|\__,_| | ||
|  | %% | ||
|  | %%  ____      _        _                 _ | ||
|  | %% |  _ \ ___| |_ _ __(_) _____   ____ _| | | ||
|  | %% | |_) / _ \ __| '__| |/ _ \ \ / / _` | | | ||
|  | %% |  _ <  __/ |_| |  | |  __/\ V / (_| | | | ||
|  | %% |_| \_\___|\__|_|  |_|\___| \_/ \__,_|_| | ||
|  | %% | ||
|  | %%  ____                    _           _ | ||
|  | %% |  _ \ ___  ___  _ __ __| | ___ _ __(_)_ __   __ _ | ||
|  | %% | |_) / _ \/ _ \| '__/ _` |/ _ \ '__| | '_ \ / _` | | ||
|  | %% |  _ <  __/ (_) | | | (_| |  __/ |  | | | | | (_| | | ||
|  | %% |_| \_\___|\___/|_|  \__,_|\___|_|  |_|_| |_|\__, | | ||
|  | %%                                              |___/ | ||
|  | 
 | ||
|  | reorder_heads(RuleNb,Head,RestHeads,RestIDs,NRestHeads,NRestIDs) :- | ||
|  | 	( chr_pp_flag(reorder_heads,on) -> | ||
|  | 		reorder_heads_main(RuleNb,Head,RestHeads,RestIDs,NRestHeads,NRestIDs) | ||
|  | 	; | ||
|  | 		NRestHeads = RestHeads, | ||
|  | 		NRestIDs = RestIDs | ||
|  | 	). | ||
|  | 
 | ||
|  | reorder_heads_main(RuleNb,Head,RestHeads,RestIDs,NRestHeads,NRestIDs) :- | ||
|  | 	term_variables(Head,Vars), | ||
|  | 	InitialData = entry([],[],Vars,RestHeads,RestIDs,RuleNb), | ||
|  | 	a_star(InitialData,FD^(chr_translate:final_data(FD)),N^EN^C^(chr_translate:expand_data(N,EN,C)),FinalData), | ||
|  | 	FinalData   = entry(RNRestHeads,RNRestIDs,_,_,_,_), | ||
|  | 	reverse(RNRestHeads,NRestHeads), | ||
|  | 	reverse(RNRestIDs,NRestIDs). | ||
|  | 
 | ||
|  | final_data(Entry) :- | ||
|  | 	Entry = entry(_,_,_,_,[],_). | ||
|  | 
 | ||
|  | expand_data(Entry,NEntry,Cost) :- | ||
|  | 	Entry = entry(Heads,IDs,Vars,NHeads,NIDs,RuleNb), | ||
|  | 	term_variables(Entry,EVars), | ||
|  | 	NEntry = entry([Head1|Heads],[ID1|IDs],Vars1,NHeads1,NIDs1,RuleNb), | ||
|  | 	select2(Head1,ID1,NHeads,NIDs,NHeads1,NIDs1), | ||
|  | 	order_score(Head1,ID1,Vars,NHeads1,RuleNb,Cost), | ||
|  | 	term_variables([Head1|Vars],Vars1). | ||
|  | 
 | ||
|  | order_score(Head,ID,KnownVars,RestHeads,RuleNb,Score) :- | ||
|  | 	functor(Head,F,A), | ||
|  | 	get_store_type(F/A,StoreType), | ||
|  | 	order_score(StoreType,Head,ID,KnownVars,RestHeads,RuleNb,Score). | ||
|  | 
 | ||
|  | order_score(default,Head,_ID,KnownVars,RestHeads,RuleNb,Score) :- | ||
|  | 	term_variables(Head,HeadVars), | ||
|  | 	term_variables(RestHeads,RestVars), | ||
|  | 	order_score_vars(HeadVars,KnownVars,RestHeads,0,Score). | ||
|  | order_score(multi_hash(Indexes),Head,_ID,KnownVars,RestHeads,RuleNb,Score) :- | ||
|  | 	order_score_indexes(Indexes,Head,KnownVars,0,Score). | ||
|  | order_score(global_ground,Head,ID,_KnownVars,_RestHeads,RuleNb,Score) :- | ||
|  | 	functor(Head,F,A), | ||
|  | 	( get_pragma_unique(RuleNb,ID,Vars), | ||
|  |           Vars == [] -> | ||
|  | 		Score = 1		% guaranteed O(1) | ||
|  | 	; A == 0 ->			% flag constraint | ||
|  | 		Score = 10		% O(1)? [CHECK: no deleted/triggered/... constraints in store?] | ||
|  | 	; A > 0 -> | ||
|  | 		Score = 100 | ||
|  | 	). | ||
|  | 
 | ||
|  | order_score(multi_store(StoreTypes),Head,ID,KnownVars,RestHeads,RuleNb,Score) :- | ||
|  | 	find_with_var_identity( | ||
|  | 		S, | ||
|  | 		t(Head,KnownVars,RestHeads), | ||
|  | 		( member(ST,StoreTypes), chr_translate:order_score(ST,Head,ID,KnownVars,RestHeads,RuleNb,S) ), | ||
|  | 		Scores | ||
|  | 	), | ||
|  | 	min_list(Scores,Score). | ||
|  | 
 | ||
|  | 
 | ||
|  | order_score_indexes([],_,_,Score,Score) :- | ||
|  | 	Score > 0. | ||
|  | order_score_indexes([I|Is],Head,KnownVars,Score,NScore) :- | ||
|  | 	multi_hash_key_args(I,Head,Args), | ||
|  | 	( forall(Arg,Args,hprolog:memberchk_eq(Arg,KnownVars)) -> | ||
|  | 		Score1 is Score + 10 | ||
|  | 	; | ||
|  | 		Score1 = Score | ||
|  | 	), | ||
|  | 	order_score_indexes(Is,Head,KnownVars,Score1,NScore). | ||
|  | 
 | ||
|  | order_score_vars([],_,_,Score,NScore) :- | ||
|  | 	( Score == 0 -> | ||
|  | 		NScore = 0 | ||
|  | 	; | ||
|  | 		NScore = Score | ||
|  | 	). | ||
|  | order_score_vars([V|Vs],KnownVars,RestVars,Score,NScore) :- | ||
|  | 	( memberchk_eq(V,KnownVars) -> | ||
|  | 		TScore is Score + 10 | ||
|  | 	; memberchk_eq(V,RestVars) -> | ||
|  | 		TScore is Score + 100 | ||
|  | 	; | ||
|  | 		TScore = Score | ||
|  | 	), | ||
|  | 	order_score_vars(Vs,KnownVars,RestVars,TScore,NScore). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %%  ___       _ _       _ | ||
|  | %% |_ _|_ __ | (_)_ __ (_)_ __   __ _ | ||
|  | %%  | || '_ \| | | '_ \| | '_ \ / _` | | ||
|  | %%  | || | | | | | | | | | | | | (_| | | ||
|  | %% |___|_| |_|_|_|_| |_|_|_| |_|\__, | | ||
|  | %%                              |___/ | ||
|  | 
 | ||
|  | %% SWI begin | ||
|  | create_get_mutable_ref(V,M,GM) :- GM = (M = mutable(V)). | ||
|  | %% SWI end | ||
|  | 
 | ||
|  | %% SICStus begin | ||
|  | %% create_get_mutable_ref(V,M,GM) :- GM = get_mutable(V,M). | ||
|  | %% SICStus end | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | %%  _   _ _   _ _ _ _ | ||
|  | %% | | | | |_(_) (_) |_ _   _ | ||
|  | %% | | | | __| | | | __| | | | | ||
|  | %% | |_| | |_| | | | |_| |_| | | ||
|  | %%  \___/ \__|_|_|_|\__|\__, | | ||
|  | %%                      |___/ | ||
|  | 
 | ||
|  | gen_var(_). | ||
|  | gen_vars(N,Xs) :- | ||
|  |    length(Xs,N). | ||
|  | 
 | ||
|  | head_info(Head,A,Vars,Susp,VarsSusp,HeadPairs) :- | ||
|  |    vars_susp(A,Vars,Susp,VarsSusp), | ||
|  |    Head =.. [_|Args], | ||
|  |    pairup(Args,Vars,HeadPairs). | ||
|  | 
 | ||
|  | inc_id([N|Ns],[O|Ns]) :- | ||
|  |    O is N + 1. | ||
|  | dec_id([N|Ns],[M|Ns]) :- | ||
|  |    M is N - 1. | ||
|  | 
 | ||
|  | extend_id(Id,[0|Id]). | ||
|  | 
 | ||
|  | next_id([_,N|Ns],[O|Ns]) :- | ||
|  |    O is N + 1. | ||
|  | 
 | ||
|  | build_head(F,A,Id,Args,Head) :- | ||
|  |    buildName(F,A,Id,Name), | ||
|  |    Head =.. [Name|Args]. | ||
|  | 
 | ||
|  | buildName(Fct,Aty,List,Result) :- | ||
|  |    atom_concat(Fct, (/) ,FctSlash), | ||
|  |    atomic_concat(FctSlash,Aty,FctSlashAty), | ||
|  |    buildName_(List,FctSlashAty,Result). | ||
|  | 
 | ||
|  | buildName_([],Name,Name). | ||
|  | buildName_([N|Ns],Name,Result) :- | ||
|  |   buildName_(Ns,Name,Name1), | ||
|  |   atom_concat(Name1,'__',NameDash),    % '_' is a char :-( | ||
|  |   atomic_concat(NameDash,N,Result). | ||
|  | 
 | ||
|  | vars_susp(A,Vars,Susp,VarsSusp) :- | ||
|  |    length(Vars,A), | ||
|  |    append(Vars,[Susp],VarsSusp). | ||
|  | 
 | ||
|  | make_attr(N,Mask,SuspsList,Attr) :- | ||
|  | 	length(SuspsList,N), | ||
|  | 	Attr =.. [v,Mask|SuspsList]. | ||
|  | 
 | ||
|  | or_pattern(Pos,Pat) :- | ||
|  | 	Pow is Pos - 1, | ||
|  | 	Pat is 1 << Pow.      % was 2 ** X | ||
|  | 
 | ||
|  | and_pattern(Pos,Pat) :- | ||
|  | 	X is Pos - 1, | ||
|  | 	Y is 1 << X,          % was 2 ** X | ||
|  | 	Pat is (-1)*(Y + 1).	% because fx (-) is redefined | ||
|  | 
 | ||
|  | conj2list(Conj,L) :-				%% transform conjunctions to list | ||
|  |   conj2list(Conj,L,[]). | ||
|  | 
 | ||
|  | conj2list(Conj,L,T) :- | ||
|  |   Conj = (G1,G2), !, | ||
|  |   conj2list(G1,L,T1), | ||
|  |   conj2list(G2,T1,T). | ||
|  | conj2list(G,[G | T],T). | ||
|  | 
 | ||
|  | list2conj([],true). | ||
|  | list2conj([G],X) :- !, X = G. | ||
|  | list2conj([G|Gs],C) :- | ||
|  | 	( G == true ->				%% remove some redundant trues | ||
|  | 		list2conj(Gs,C) | ||
|  | 	; | ||
|  | 		C = (G,R), | ||
|  | 		list2conj(Gs,R) | ||
|  | 	). | ||
|  | 
 | ||
|  | list2disj([],fail). | ||
|  | list2disj([G],X) :- !, X = G. | ||
|  | list2disj([G|Gs],C) :- | ||
|  | 	( G == fail ->				%% remove some redundant fails | ||
|  | 		list2disj(Gs,C) | ||
|  | 	; | ||
|  | 		C = (G;R), | ||
|  | 		list2disj(Gs,R) | ||
|  | 	). | ||
|  | 
 | ||
|  | atom_concat_list([X],X) :- ! . | ||
|  | atom_concat_list([X|Xs],A) :- | ||
|  | 	atom_concat_list(Xs,B), | ||
|  | 	atomic_concat(X,B,A). | ||
|  | 
 | ||
|  | make_name(Prefix,F/A,Name) :- | ||
|  | 	atom_concat_list([Prefix,F,(/),A],Name). | ||
|  | 
 | ||
|  | set_elems([],_). | ||
|  | set_elems([X|Xs],X) :- | ||
|  | 	set_elems(Xs,X). | ||
|  | 
 | ||
|  | member2([X|_],[Y|_],X-Y). | ||
|  | member2([_|Xs],[_|Ys],P) :- | ||
|  | 	member2(Xs,Ys,P). | ||
|  | 
 | ||
|  | select2(X, Y, [X|Xs], [Y|Ys], Xs, Ys). | ||
|  | select2(X, Y, [X1|Xs], [Y1|Ys], [X1|NXs], [Y1|NYs]) :- | ||
|  | 	select2(X, Y, Xs, Ys, NXs, NYs). | ||
|  | 
 | ||
|  | pair_all_with([],_,[]). | ||
|  | pair_all_with([X|Xs],Y,[X-Y|Rest]) :- | ||
|  | 	pair_all_with(Xs,Y,Rest). | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | lookup_passive_head(Head,PreJoin,VarDict,Goal,AllSusps) :- | ||
|  | 	functor(Head,F,A), | ||
|  | 	get_store_type(F/A,StoreType), | ||
|  | 	lookup_passive_head(StoreType,Head,PreJoin,VarDict,Goal,AllSusps). | ||
|  | 
 | ||
|  | lookup_passive_head(default,Head,PreJoin,VarDict,Goal,AllSusps) :- | ||
|  | 	passive_head_via(Head,PreJoin,[],VarDict,Goal,Attr,AttrDict), | ||
|  | 	instantiate_pattern_goals(AttrDict), | ||
|  | 	get_max_constraint_index(N), | ||
|  | 	( N == 1 -> | ||
|  | 		AllSusps = Attr | ||
|  | 	; | ||
|  | 		functor(Head,F,A), | ||
|  | 		get_constraint_index(F/A,Pos), | ||
|  | 		make_attr(N,_,SuspsList,Attr), | ||
|  | 		nth1(Pos,SuspsList,AllSusps) | ||
|  | 	). | ||
|  | lookup_passive_head(multi_hash(Indexes),Head,_PreJoin,VarDict,Goal,AllSusps) :- | ||
|  | 	once(( | ||
|  | 		member(Index,Indexes), | ||
|  | 		multi_hash_key_args(Index,Head,KeyArgs), | ||
|  | 		translate(KeyArgs,VarDict,KeyArgCopies) | ||
|  | 	)), | ||
|  | 	( KeyArgCopies = [KeyCopy] -> | ||
|  | 		true | ||
|  | 	; | ||
|  | 		KeyCopy =.. [k|KeyArgCopies] | ||
|  | 	), | ||
|  | 	functor(Head,F,A), | ||
|  | 	multi_hash_via_lookup_name(F/A,Index,ViaName), | ||
|  | 	Goal =.. [ViaName,KeyCopy,AllSusps], | ||
|  | 	update_store_type(F/A,multi_hash([Index])). | ||
|  | lookup_passive_head(global_ground,Head,PreJoin,_VarDict,Goal,AllSusps) :- | ||
|  | 	functor(Head,F,A), | ||
|  | 	global_ground_store_name(F/A,StoreName), | ||
|  | 	make_get_store_goal(StoreName,AllSusps,Goal), % Goal = nb_getval(StoreName,AllSusps), | ||
|  | 	update_store_type(F/A,global_ground). | ||
|  | lookup_passive_head(multi_store(StoreTypes),Head,PreJoin,VarDict,Goal,AllSusps) :- | ||
|  | 	once(( | ||
|  | 		member(ST,StoreTypes), | ||
|  | 		lookup_passive_head(ST,Head,PreJoin,VarDict,Goal,AllSusps) | ||
|  | 	)). | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | assume_constraint_stores([]). | ||
|  | assume_constraint_stores([C|Cs]) :- | ||
|  | 	( \+ may_trigger(C), | ||
|  | 	  is_attached(C), | ||
|  | 	  get_store_type(C,default) -> | ||
|  | 		get_indexed_arguments(C,IndexedArgs), | ||
|  | 		findall(Index,(sublist(Index,IndexedArgs), Index \== []),Indexes), | ||
|  | 		assumed_store_type(C,multi_store([multi_hash(Indexes),global_ground])) | ||
|  | 	; | ||
|  | 		true | ||
|  | 	), | ||
|  | 	assume_constraint_stores(Cs). | ||
|  | 
 | ||
|  | get_indexed_arguments(C,IndexedArgs) :- | ||
|  | 	C = F/A, | ||
|  | 	get_indexed_arguments(1,A,C,IndexedArgs). | ||
|  | 
 | ||
|  | get_indexed_arguments(I,N,C,L) :- | ||
|  | 	( I > N -> | ||
|  | 		L = [] | ||
|  | 	;	( is_indexed_argument(C,I) -> | ||
|  | 			L = [I|T] | ||
|  | 		; | ||
|  | 			L = T | ||
|  | 		), | ||
|  | 		J is I + 1, | ||
|  | 		get_indexed_arguments(J,N,C,T) | ||
|  | 	). | ||
|  | 
 | ||
|  | validate_store_type_assumptions([]). | ||
|  | validate_store_type_assumptions([C|Cs]) :- | ||
|  | 	validate_store_type_assumption(C), | ||
|  | 	validate_store_type_assumptions(Cs). | ||
|  | 
 | ||
|  | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|  | 
 | ||
|  | %% SWI begin | ||
|  | verbosity_on :- prolog_flag(verbose,V), V == yes. | ||
|  | %% SWI end | ||
|  | 
 | ||
|  | %% SICStus begin | ||
|  | %% verbosity_on.  % at the moment | ||
|  | %% SICStus end |