894 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
		
		
			
		
	
	
			894 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| 
								 | 
							
								%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
							 | 
						||
| 
								 | 
							
								%  Constraint Handling Rules			      version 2.2 %
							 | 
						||
| 
								 | 
							
								%								  %
							 | 
						||
| 
								 | 
							
								%  (c) Copyright 1996-98					  %
							 | 
						||
| 
								 | 
							
								%  LMU, Muenchen						  %
							 | 
						||
| 
								 | 
							
								%								  %
							 | 
						||
| 
								 | 
							
								%  File:   chr.pl						  %
							 | 
						||
| 
								 | 
							
								%  Author: Christian Holzbaur		christian@ai.univie.ac.at %
							 | 
						||
| 
								 | 
							
								%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% The CHR runtime system,
							 | 
						||
| 
								 | 
							
								% the constraint store.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Two functions: a) storage b) reactivation triggered by bindings
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Reactivation is symmetric: if two variables with suspensions
							 | 
						||
| 
								 | 
							
								% are unified, both suspensions run. (Both variables got more
							 | 
						||
| 
								 | 
							
								% constrained)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% *** Sequence of wakeups determines termination of handler leq ***
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Another sequence that could matter is the one
							 | 
						||
| 
								 | 
							
								% generated by the iterators
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Layout:
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	   suspension(Id,State,Closure,Generation,PropagationHistory,F|Args)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%   Id is 1st to allow for direct comparisons (sort) and avoids
							 | 
						||
| 
								 | 
							
								%   unifiability if the Id is nonvar.
							 | 
						||
| 
								 | 
							
								%   F is the constraint functor
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- module( chr,
							 | 
						||
| 
								 | 
							
									[
							 | 
						||
| 
								 | 
							
									  find_constraint/2,
							 | 
						||
| 
								 | 
							
									  find_constraint/3,
							 | 
						||
| 
								 | 
							
									  findall_constraints/2,
							 | 
						||
| 
								 | 
							
									  findall_constraints/3,
							 | 
						||
| 
								 | 
							
									  remove_constraint/1,
							 | 
						||
| 
								 | 
							
									  current_handler/2,
							 | 
						||
| 
								 | 
							
									  current_constraint/2,
							 | 
						||
| 
								 | 
							
									  unconstrained/1,
							 | 
						||
| 
								 | 
							
									  notify_constrained/1,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									  chr_trace/0, chr_notrace/0,
							 | 
						||
| 
								 | 
							
									  chr_debug/0, chr_nodebug/0, chr_debugging/0,
							 | 
						||
| 
								 | 
							
									  chr_leash/1, chr_spy/1, chr_nospy/1
							 | 
						||
| 
								 | 
							
								      ]).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- use_module( library('chr/getval')).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- use_module( library(lists),
							 | 
						||
| 
								 | 
							
									[
							 | 
						||
| 
								 | 
							
									  append/3,
							 | 
						||
| 
								 | 
							
									  member/2,
							 | 
						||
| 
								 | 
							
									  is_list/1,
							 | 
						||
| 
								 | 
							
									  nth/3,
							 | 
						||
| 
								 | 
							
									  select/3
							 | 
						||
| 
								 | 
							
									]).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- use_module( library(terms),
							 | 
						||
| 
								 | 
							
									[
							 | 
						||
| 
								 | 
							
									  term_variables/2,
							 | 
						||
| 
								 | 
							
									  subsumes_chk/2,
							 | 
						||
| 
								 | 
							
									  subsumes/2
							 | 
						||
| 
								 | 
							
									]).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- use_module( library(assoc),			% propagation history
							 | 
						||
| 
								 | 
							
									[
							 | 
						||
| 
								 | 
							
									  empty_assoc/1,
							 | 
						||
| 
								 | 
							
									  put_assoc/4,
							 | 
						||
| 
								 | 
							
									  get_assoc/3,
							 | 
						||
| 
								 | 
							
									  assoc_to_list/2
							 | 
						||
| 
								 | 
							
								      ]).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- use_module(library('chr/sbag')).   % link to sbag_l.pl or sbag_a.pl
							 | 
						||
| 
								 | 
							
								:- use_module(library('chr/chrcmp')).
							 | 
						||
| 
								 | 
							
								:- use_module(library('chr/trace')).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- use_module(library(atts)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- attribute locked/0, exposed/1, dbg_state/1.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Problem with cyclic structures:
							 | 
						||
| 
								 | 
							
								%   error reporters seem to use write ...
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								:- multifile
							 | 
						||
| 
								 | 
							
									user:portray/1,
							 | 
						||
| 
								 | 
							
									user:portray_message/2,
							 | 
						||
| 
								 | 
							
									user:goal_expansion/3.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- dynamic
							 | 
						||
| 
								 | 
							
									user:portray/1,
							 | 
						||
| 
								 | 
							
									user:portray_message/2,
							 | 
						||
| 
								 | 
							
									user:goal_expansion/3.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								user:portray( Susp) :-
							 | 
						||
| 
								 | 
							
									Susp =.. [suspension,Id,Mref,_,_,_,_|_],
							 | 
						||
| 
								 | 
							
									nonvar( Mref),
							 | 
						||
| 
								 | 
							
									!,
							 | 
						||
| 
								 | 
							
									write('<c'), write(Id), write('>').	% (c)onstraint
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								user:portray( '$want_duplicates'(_,Term)) :- !, % cf. attribute_goal/2
							 | 
						||
| 
								 | 
							
									prolog_flag( toplevel_print_options, Options),
							 | 
						||
| 
								 | 
							
									write_term( Term, Options).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- initialization
							 | 
						||
| 
								 | 
							
									setval( id, 0).		% counter for portray/debugger
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								user:portray_message( error, chr(multiple_handlers(Old,New,Module))) :- !,
							 | 
						||
| 
								 | 
							
									format( user_error, '{CHR ERROR: registering ~p, module ~p already hosts ~p}~n',
							 | 
						||
| 
								 | 
							
									  [New,Module,Old]).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% -----------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% *** MACROS ***
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								user:goal_expansion( lock_some(L),		 chr, Exp) :- is_list(L),
							 | 
						||
| 
								 | 
							
									unravel( L, lock, Exp).
							 | 
						||
| 
								 | 
							
								user:goal_expansion( unlock_some(L),		 chr, Exp) :- is_list(L),
							 | 
						||
| 
								 | 
							
									unravel( L, unlock, Exp).
							 | 
						||
| 
								 | 
							
								user:goal_expansion( via([],V), 		 chr, global_term_ref_1(V)).
							 | 
						||
| 
								 | 
							
								user:goal_expansion( via([X],V),		 chr, via_1(X,V)).
							 | 
						||
| 
								 | 
							
								user:goal_expansion( via([X,Y],V),		 chr, via_2(X,Y,V)).
							 | 
						||
| 
								 | 
							
								user:goal_expansion( via([X,Y,Z],V),		 chr, via_3(X,Y,Z,V)).
							 | 
						||
| 
								 | 
							
								user:goal_expansion( load_args(S,State,Args),	 chr, Exp) :-
							 | 
						||
| 
								 | 
							
									is_list( Args),
							 | 
						||
| 
								 | 
							
									Susp =.. [suspension,_,Mref,_,_,_,_|Args],
							 | 
						||
| 
								 | 
							
									Exp = ( S=Susp, get_mutable( State, Mref) ).
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								user:goal_expansion( nd_init_iteration(V,_,_,Att,S), _, Exp) :-
							 | 
						||
| 
								 | 
							
									arg( 1, Att, Stack),
							 | 
						||
| 
								 | 
							
									Exp = ( get_atts(V,Att), chr:sbag_member(S,Stack) ).
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								user:goal_expansion( init_iteration(V,_,_,Att,L), _, Exp) :-
							 | 
						||
| 
								 | 
							
									arg( 1, Att, Stack),
							 | 
						||
| 
								 | 
							
									Exp = ( get_atts(V,Att), chr:iter_init(Stack,L) ).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								unravel( [],	 _, true).
							 | 
						||
| 
								 | 
							
								unravel( [X|Xs], F, (G,Gs)) :-
							 | 
						||
| 
								 | 
							
									G =.. [F,X],
							 | 
						||
| 
								 | 
							
									unravel( Xs, F, Gs).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% ----------------------- runtime user predicates -----------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								remove_constraint( Susp) :-
							 | 
						||
| 
								 | 
							
									nonvar( Susp),
							 | 
						||
| 
								 | 
							
									functor( Susp, suspension, N),
							 | 
						||
| 
								 | 
							
									N >= 6,
							 | 
						||
| 
								 | 
							
									!,
							 | 
						||
| 
								 | 
							
									debug_event( remove(Susp)),
							 | 
						||
| 
								 | 
							
									remove_constraint_internal( Susp, Vars),
							 | 
						||
| 
								 | 
							
									arg( 3, Susp, Module:_),
							 | 
						||
| 
								 | 
							
									arg( 6, Susp, F),
							 | 
						||
| 
								 | 
							
									A is N-6,
							 | 
						||
| 
								 | 
							
									Module:detach( F/A, Susp, Vars). 
							 | 
						||
| 
								 | 
							
								remove_constraint( S) :-
							 | 
						||
| 
								 | 
							
									raise_exception( type_error(remove_constraint(S),1,'a constraint object',S)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								find_constraint( Term, Susp) :-
							 | 
						||
| 
								 | 
							
									global_term_ref_1( Global),
							 | 
						||
| 
								 | 
							
									find_constraint( Global, Term, Susp).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								find_constraint( V, Term, Susp) :- var( V), !,
							 | 
						||
| 
								 | 
							
									find_constraint_internal( V, Term, Susp, active, _).
							 | 
						||
| 
								 | 
							
								find_constraint( A, B, C) :-
							 | 
						||
| 
								 | 
							
									raise_exception( instantiation_error( find_constraint(A,B,C), 1)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								find_constraint_internal( V, Term, Susp, State, Module) :-
							 | 
						||
| 
								 | 
							
									constraint( Handler, F/A, Att),
							 | 
						||
| 
								 | 
							
									functor( Term, F, A),			% prune some
							 | 
						||
| 
								 | 
							
									arg( 1, Att, Stack),
							 | 
						||
| 
								 | 
							
									current_handler( Handler, Module),
							 | 
						||
| 
								 | 
							
									Module:get_atts( V, Att),
							 | 
						||
| 
								 | 
							
									length( Args, A),
							 | 
						||
| 
								 | 
							
									Try =.. [F|Args],
							 | 
						||
| 
								 | 
							
									sbag_member( Susp, Stack),
							 | 
						||
| 
								 | 
							
									Susp =.. [suspension,_,Mref,_,_,_,_|Args],
							 | 
						||
| 
								 | 
							
									get_mutable( State, Mref),
							 | 
						||
| 
								 | 
							
									subsumes( Term, Try).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Test for unconstrained var
							 | 
						||
| 
								 | 
							
								% Used by some math solvers
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								unconstrained( X) :-
							 | 
						||
| 
								 | 
							
									% var(X), prolog:'$get_cva'(X,[],_).
							 | 
						||
| 
								 | 
							
									find_constraint( X, _, _), !, fail.
							 | 
						||
| 
								 | 
							
								unconstrained( _).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								findall_constraints( C, L) :-
							 | 
						||
| 
								 | 
							
									global_term_ref_1( Global),
							 | 
						||
| 
								 | 
							
									findall_constraints( Global, C, L).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								findall_constraints( V, C, L) :- var( V), !,
							 | 
						||
| 
								 | 
							
									findall( M:Att, (
							 | 
						||
| 
								 | 
							
											    constraint( H, F/A, Att),
							 | 
						||
| 
								 | 
							
											    functor( C, F, A),
							 | 
						||
| 
								 | 
							
											    current_handler( H, M)
							 | 
						||
| 
								 | 
							
											),
							 | 
						||
| 
								 | 
							
											Agenda),
							 | 
						||
| 
								 | 
							
									findall_constraints( Agenda, C, V, L, []).
							 | 
						||
| 
								 | 
							
								findall_constraints( V, C, L) :-
							 | 
						||
| 
								 | 
							
									raise_exception( instantiation_error( findall_constraints(V,C,L), 1)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								findall_constraints( [],		  _, _) --> [].
							 | 
						||
| 
								 | 
							
								findall_constraints( [Module:Att|Agenda], C, V) -->
							 | 
						||
| 
								 | 
							
									( {
							 | 
						||
| 
								 | 
							
									    arg( 1, Att, Stack),
							 | 
						||
| 
								 | 
							
									    Module:get_atts( V, Att),
							 | 
						||
| 
								 | 
							
									    iter_init( Stack, State)
							 | 
						||
| 
								 | 
							
									  } ->
							 | 
						||
| 
								 | 
							
									    findall_constraints_( State, C, Module)
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    []
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									findall_constraints( Agenda, C, V).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								findall_constraints_( State, _,       _) --> {iter_last(State)}.
							 | 
						||
| 
								 | 
							
								findall_constraints_( State, General, Module) -->
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
									    iter_next( State, S, Next)
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									( {
							 | 
						||
| 
								 | 
							
									    S =.. [suspension,_,Mref,_,_,_,F|Args],
							 | 
						||
| 
								 | 
							
									    get_mutable( active, Mref),
							 | 
						||
| 
								 | 
							
									    Term =.. [F|Args],
							 | 
						||
| 
								 | 
							
									    subsumes_chk( General, Term)
							 | 
						||
| 
								 | 
							
									  } ->
							 | 
						||
| 
								 | 
							
										[ Term#S ]
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
										[]
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									findall_constraints_( Next, General, Module).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Decorate a constraint Term from Module
							 | 
						||
| 
								 | 
							
								% with a module prefix if needed.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								module_wrap( Term, Module, Wrapped) :-
							 | 
						||
| 
								 | 
							
									prolog_flag( typein_module, Typein),
							 | 
						||
| 
								 | 
							
									( Module == Typein ->
							 | 
						||
| 
								 | 
							
									    Wrapped = Term
							 | 
						||
| 
								 | 
							
									; predicate_property( Typein:Term, imported_from(_)) ->
							 | 
						||
| 
								 | 
							
									    Wrapped = Term
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    Wrapped = Module:Term
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% -----------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   Two namespaces handler/module actually only justified if there
							 | 
						||
| 
								 | 
							
								   can be more than one handler per module ...
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- dynamic handler/2.
							 | 
						||
| 
								 | 
							
								:- dynamic constraint/3.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								current_handler( Handler, Module) :-
							 | 
						||
| 
								 | 
							
									handler( Handler, Module).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								current_constraint( Handler, C) :-
							 | 
						||
| 
								 | 
							
									constraint( Handler, C, _).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								register_handler( Handler, Cs, Slots) :-
							 | 
						||
| 
								 | 
							
									prolog_load_context( module, Module),
							 | 
						||
| 
								 | 
							
									( handler(Other,Module),
							 | 
						||
| 
								 | 
							
									  Other \== Handler ->
							 | 
						||
| 
								 | 
							
									    raise_exception( chr(multiple_handlers(Other,Handler,Module)))
							 | 
						||
| 
								 | 
							
									; handler( Handler, Module) ->
							 | 
						||
| 
								 | 
							
									    true				% simple reload
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    assert( handler(Handler,Module))
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									retractall( constraint(Handler,_,_)),
							 | 
						||
| 
								 | 
							
									reg_handler( Cs, Slots, Handler).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								reg_handler( [],     [],     _).
							 | 
						||
| 
								 | 
							
								reg_handler( [C|Cs], [S|Ss], Handler) :-
							 | 
						||
| 
								 | 
							
									assert( constraint(Handler,C,S)),
							 | 
						||
| 
								 | 
							
									reg_handler( Cs, Ss, Handler).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% ----------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								notify_constrained( X) :- var( X),
							 | 
						||
| 
								 | 
							
									findall( M, handler(_,M), Modules),
							 | 
						||
| 
								 | 
							
									notify_constrained( Modules, X).
							 | 
						||
| 
								 | 
							
								notify_constrained( X) :- nonvar( X),
							 | 
						||
| 
								 | 
							
									raise_exception( instantitation_error( notify_constrained(X),1)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								notify_constrained( [], _).
							 | 
						||
| 
								 | 
							
								notify_constrained( [M|Ms], X) :-
							 | 
						||
| 
								 | 
							
									M:get_suspensions( X, S),
							 | 
						||
| 
								 | 
							
									run_suspensions( S),
							 | 
						||
| 
								 | 
							
									notify_constrained( Ms, X).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% support for verify_attributes/3, notify_constrained/1
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Approximation because debug state might change between calls ...
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								run_suspensions( Slots) :-
							 | 
						||
| 
								 | 
							
									getval( debug, State),
							 | 
						||
| 
								 | 
							
									( State == off ->
							 | 
						||
| 
								 | 
							
									    run_suspensions_loop( Slots)
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    run_suspensions_loop_d( Slots)
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									true.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								run_suspensions_loop( []).
							 | 
						||
| 
								 | 
							
								run_suspensions_loop( [A|As]) :-
							 | 
						||
| 
								 | 
							
									arg( 1, A, Stack),
							 | 
						||
| 
								 | 
							
									iter_init( Stack, State),
							 | 
						||
| 
								 | 
							
									run_suspensions_( State),
							 | 
						||
| 
								 | 
							
									run_suspensions_loop( As).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								run_suspensions_loop_d( []).
							 | 
						||
| 
								 | 
							
								run_suspensions_loop_d( [A|As]) :-
							 | 
						||
| 
								 | 
							
									arg( 1, A, Stack),
							 | 
						||
| 
								 | 
							
									iter_init( Stack, State),
							 | 
						||
| 
								 | 
							
									run_suspensions_d( State),
							 | 
						||
| 
								 | 
							
									run_suspensions_loop_d( As).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Transition active->triggered->removed instead of
							 | 
						||
| 
								 | 
							
								% active->removed is to avoid early gc of suspensions.
							 | 
						||
| 
								 | 
							
								% The suspension's generation is incremented to signal
							 | 
						||
| 
								 | 
							
								% to the revive scheme that the constraint has been
							 | 
						||
| 
								 | 
							
								% processed already.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								run_suspensions_( State) :- iter_last( State).
							 | 
						||
| 
								 | 
							
								run_suspensions_( State) :-
							 | 
						||
| 
								 | 
							
									iter_next( State, S, Next),
							 | 
						||
| 
								 | 
							
									arg( 2, S, Mref),
							 | 
						||
| 
								 | 
							
									get_mutable( Status, Mref),
							 | 
						||
| 
								 | 
							
									( Status==active ->
							 | 
						||
| 
								 | 
							
									    update_mutable( triggered, Mref),
							 | 
						||
| 
								 | 
							
									    arg( 4, S, Gref),
							 | 
						||
| 
								 | 
							
									    get_mutable( Gen, Gref),
							 | 
						||
| 
								 | 
							
									    Generation is Gen+1,
							 | 
						||
| 
								 | 
							
									    update_mutable( Generation, Gref),
							 | 
						||
| 
								 | 
							
									    arg( 3, S, Goal),
							 | 
						||
| 
								 | 
							
									    call( Goal),
							 | 
						||
| 
								 | 
							
									    get_mutable( Post, Mref),
							 | 
						||
| 
								 | 
							
									    ( Post==triggered ->
							 | 
						||
| 
								 | 
							
										update_mutable( removed, Mref)
							 | 
						||
| 
								 | 
							
									    ;
							 | 
						||
| 
								 | 
							
										true
							 | 
						||
| 
								 | 
							
									    )
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    true
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									run_suspensions_( Next).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								run_suspensions_d( State) :- iter_last( State).
							 | 
						||
| 
								 | 
							
								run_suspensions_d( State) :-
							 | 
						||
| 
								 | 
							
									iter_next( State, S, Next),
							 | 
						||
| 
								 | 
							
									arg( 2, S, Mref),
							 | 
						||
| 
								 | 
							
									get_mutable( Status, Mref),
							 | 
						||
| 
								 | 
							
									( Status==active ->
							 | 
						||
| 
								 | 
							
									    update_mutable( triggered, Mref),
							 | 
						||
| 
								 | 
							
									    arg( 4, S, Gref),
							 | 
						||
| 
								 | 
							
									    get_mutable( Gen, Gref),
							 | 
						||
| 
								 | 
							
									    Generation is Gen+1,
							 | 
						||
| 
								 | 
							
									    update_mutable( Generation, Gref),
							 | 
						||
| 
								 | 
							
									    arg( 3, S, Goal),
							 | 
						||
| 
								 | 
							
									    byrd( S, Goal),
							 | 
						||
| 
								 | 
							
									    get_mutable( Post, Mref),
							 | 
						||
| 
								 | 
							
									    ( Post==triggered ->
							 | 
						||
| 
								 | 
							
										update_mutable( removed, Mref)
							 | 
						||
| 
								 | 
							
									    ;
							 | 
						||
| 
								 | 
							
										true
							 | 
						||
| 
								 | 
							
									    )
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    true
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									run_suspensions_d( Next).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								byrd( Self, Goal) :-
							 | 
						||
| 
								 | 
							
									(   debug_event( wake(Self)), call( Goal)
							 | 
						||
| 
								 | 
							
									;   debug_event( fail(Self)), !, fail
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									(   debug_event( exit(Self))
							 | 
						||
| 
								 | 
							
									;   debug_event( redo(Self)), fail
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Merge 2 sorted lists of Name/1 terms.
							 | 
						||
| 
								 | 
							
								% The argument of each term is a sbag.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								merge_attributes( [],	  Bs, Bs).
							 | 
						||
| 
								 | 
							
								merge_attributes( [A|As], Bs, Cs) :-
							 | 
						||
| 
								 | 
							
									merge_attributes( Bs, Cs, A, As).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								merge_attributes( [],	  [A|As], A, As).
							 | 
						||
| 
								 | 
							
								merge_attributes( [B|Bs], Cs,	  A, As) :-
							 | 
						||
| 
								 | 
							
									functor( A, NameA, 1),
							 | 
						||
| 
								 | 
							
									functor( B, NameB, 1),
							 | 
						||
| 
								 | 
							
									compare( R, NameA, NameB),
							 | 
						||
| 
								 | 
							
									( R == < -> Cs = [A|Css], merge_attributes( As, Css, B, Bs)
							 | 
						||
| 
								 | 
							
									; R == > -> Cs = [B|Css], merge_attributes( Bs, Css, A, As)
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    Cs = [C|Css],
							 | 
						||
| 
								 | 
							
									    functor( C, NameA, 1),
							 | 
						||
| 
								 | 
							
									    arg( 1, A, StackA),
							 | 
						||
| 
								 | 
							
									    arg( 1, B, StackB),
							 | 
						||
| 
								 | 
							
									    arg( 1, C, StackC),
							 | 
						||
| 
								 | 
							
									    sbag_union( StackA, StackB, StackC),
							 | 
						||
| 
								 | 
							
									    merge_attributes( As, Bs, Css)
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								show_bag( Bag) :-
							 | 
						||
| 
								 | 
							
									iter_init( Bag, State),
							 | 
						||
| 
								 | 
							
									show_bag_( State),
							 | 
						||
| 
								 | 
							
									nl.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								show_bag_( State) :- iter_last( State).
							 | 
						||
| 
								 | 
							
								show_bag_( State) :-
							 | 
						||
| 
								 | 
							
									iter_next( State, S, Next),
							 | 
						||
| 
								 | 
							
									arg( 2, S, Ref),
							 | 
						||
| 
								 | 
							
									get_mutable( St, Ref),
							 | 
						||
| 
								 | 
							
									format( ' ~p:~p', [S,St]),
							 | 
						||
| 
								 | 
							
									show_bag_( Next).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Support for attribute_goal/2.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Complication: the Sicstus kernel removes duplicates
							 | 
						||
| 
								 | 
							
								% via call_residue/2 - that includes the toplevel.
							 | 
						||
| 
								 | 
							
								% We may want to see them ->
							 | 
						||
| 
								 | 
							
								%   tag Term with Suspension, 'untag' via portray/1
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Called with a list of slots once per module
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								attribute_goals( L, Goal, Module) :-
							 | 
						||
| 
								 | 
							
									attribute_goal_loop( L, Module, GL, []),
							 | 
						||
| 
								 | 
							
									l2c( GL, Goal).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								attribute_goal_loop( [],     _) --> [].
							 | 
						||
| 
								 | 
							
								attribute_goal_loop( [A|As], Mod) -->
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
									    arg( 1, A, Stack),
							 | 
						||
| 
								 | 
							
									    iter_init( Stack, State)
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									attgs_( State, Mod),
							 | 
						||
| 
								 | 
							
									attribute_goal_loop( As, Mod).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								attgs_( State, _) --> {iter_last( State)}.
							 | 
						||
| 
								 | 
							
								attgs_( State, Module) -->
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
									    iter_next( State, S, Next),
							 | 
						||
| 
								 | 
							
									    S =.. [suspension,_,Mref,_,_,_,F|Args]
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									( {get_mutable(active,Mref)} ->
							 | 
						||
| 
								 | 
							
									     {
							 | 
						||
| 
								 | 
							
									       Term =.. [F|Args],
							 | 
						||
| 
								 | 
							
									       module_wrap( Term, Module, Wrapped)
							 | 
						||
| 
								 | 
							
									     },
							 | 
						||
| 
								 | 
							
									     [ '$want_duplicates'(S,Wrapped) ]
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									     []
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									attgs_( Next, Module).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% fail for empty list
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								l2c( [C], C) :- !.
							 | 
						||
| 
								 | 
							
								l2c( [C|Cs], (C,Cj)) :-
							 | 
						||
| 
								 | 
							
									l2c( Cs, Cj).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Unlink removed constraints cleanly from all chains
							 | 
						||
| 
								 | 
							
								% Still need gc state because of wake,
							 | 
						||
| 
								 | 
							
								% but re-insertion = insert because of complete removal.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								chr_gc :-
							 | 
						||
| 
								 | 
							
									global_term_ref_1( Global),
							 | 
						||
| 
								 | 
							
									findall( M, handler(_,M), Modules),
							 | 
						||
| 
								 | 
							
									chr_gcm( Modules, Global).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								chr_gcm( [],	 _).
							 | 
						||
| 
								 | 
							
								chr_gcm( [M|Ms], Global) :-
							 | 
						||
| 
								 | 
							
									M:get_suspensions( Global, AllS),
							 | 
						||
| 
								 | 
							
									term_variables( [Global|AllS], Vars),	% AllS may be ground
							 | 
						||
| 
								 | 
							
									chr_gcv( Vars, M),
							 | 
						||
| 
								 | 
							
									chr_gcm( Ms, Global).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Have compiler generated support?
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								chr_gcv( [],	 _).
							 | 
						||
| 
								 | 
							
								chr_gcv( [V|Vs], M) :-
							 | 
						||
| 
								 | 
							
									M:get_suspensions( V, Old),
							 | 
						||
| 
								 | 
							
									chr_gcb( Old, New),
							 | 
						||
| 
								 | 
							
									M:put_suspensions( V, New),
							 | 
						||
| 
								 | 
							
									chr_gcv( Vs, M).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								chr_gcb( [],	 []).
							 | 
						||
| 
								 | 
							
								chr_gcb( [S|Ss], [Sgc|Ts]) :-
							 | 
						||
| 
								 | 
							
									arg( 1, S, Bag),
							 | 
						||
| 
								 | 
							
									iter_init( Bag, State),
							 | 
						||
| 
								 | 
							
									functor( S, N, 1),
							 | 
						||
| 
								 | 
							
									functor( T, N, 1),
							 | 
						||
| 
								 | 
							
									gc_bag( State, Lgc),
							 | 
						||
| 
								 | 
							
									( Lgc==[] ->
							 | 
						||
| 
								 | 
							
									    Sgc = -T
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    Sgc = T,
							 | 
						||
| 
								 | 
							
									    list_to_sbag( Lgc, BagGc),
							 | 
						||
| 
								 | 
							
									    arg( 1, T, BagGc)
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									chr_gcb( Ss, Ts).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								gc_bag( State, []) :- iter_last( State).
							 | 
						||
| 
								 | 
							
								gc_bag( State, L) :-
							 | 
						||
| 
								 | 
							
									iter_next( State, Susp, Next),
							 | 
						||
| 
								 | 
							
									arg( 2, Susp, Mref),
							 | 
						||
| 
								 | 
							
									get_mutable( SuspState, Mref),
							 | 
						||
| 
								 | 
							
									( SuspState==removed ->
							 | 
						||
| 
								 | 
							
									    L = Tail,
							 | 
						||
| 
								 | 
							
									    update_mutable( gc, Mref)
							 | 
						||
| 
								 | 
							
									; SuspState==gc ->
							 | 
						||
| 
								 | 
							
									    L = Tail
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    L = [Susp|Tail]
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									gc_bag( Next, Tail).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% --------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Incremental allocation & activation of constraints.
							 | 
						||
| 
								 | 
							
								% Attachment code of closures to variables is generated
							 | 
						||
| 
								 | 
							
								% by the compiler.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% States {passive(Term),inactive,triggered,active,removed,gc}
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- meta_predicate allocate_constraint(:,-,+,+).
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								allocate_constraint( Closure, Self, F, Args) :-
							 | 
						||
| 
								 | 
							
									empty_history( History),
							 | 
						||
| 
								 | 
							
									create_mutable( passive(Args), Mref),
							 | 
						||
| 
								 | 
							
									create_mutable( 0, Gref),
							 | 
						||
| 
								 | 
							
									create_mutable( History, Href),
							 | 
						||
| 
								 | 
							
									gen_id( Id),
							 | 
						||
| 
								 | 
							
									Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args].
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% activate_constraint( -, +, -).
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% The transition gc->active should be rare
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								activate_constraint( Vars, Susp, Generation) :-
							 | 
						||
| 
								 | 
							
									arg( 2, Susp, Mref),
							 | 
						||
| 
								 | 
							
									get_mutable( State, Mref),
							 | 
						||
| 
								 | 
							
									update_mutable( active, Mref),
							 | 
						||
| 
								 | 
							
									( nonvar(Generation) ->			% aih
							 | 
						||
| 
								 | 
							
									    true
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    arg( 4, Susp, Gref),
							 | 
						||
| 
								 | 
							
									    get_mutable( Gen, Gref),
							 | 
						||
| 
								 | 
							
									    Generation is Gen+1,
							 | 
						||
| 
								 | 
							
									    update_mutable( Generation, Gref)
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									( compound(State) ->			% passive/1
							 | 
						||
| 
								 | 
							
									    term_variables( State, Vs),
							 | 
						||
| 
								 | 
							
									    none_locked( Vs),
							 | 
						||
| 
								 | 
							
									    global_term_ref_1( Global),
							 | 
						||
| 
								 | 
							
									    Vars = [Global|Vs]
							 | 
						||
| 
								 | 
							
									; State==gc ->				% removed from all chains
							 | 
						||
| 
								 | 
							
									    Susp =.. [_,_,_,_,_,_,_|Args],
							 | 
						||
| 
								 | 
							
									    term_variables( Args, Vs),
							 | 
						||
| 
								 | 
							
									    global_term_ref_1( Global),
							 | 
						||
| 
								 | 
							
									    Vars = [Global|Vs]
							 | 
						||
| 
								 | 
							
									; State==removed ->			% the price for eager removal ...
							 | 
						||
| 
								 | 
							
									    Susp =.. [_,_,_,_,_,_,_|Args],
							 | 
						||
| 
								 | 
							
									    term_variables( Args, Vs),
							 | 
						||
| 
								 | 
							
									    global_term_ref_1( Global),
							 | 
						||
| 
								 | 
							
									    Vars = [Global|Vs]
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    Vars = []
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Combination of the prev. two
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								:- meta_predicate insert_constraint_internal(-,-,:,+,+).
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								insert_constraint_internal( [Global|Vars], Self, Closure, F, Args) :-
							 | 
						||
| 
								 | 
							
									term_variables( Args, Vars),
							 | 
						||
| 
								 | 
							
									none_locked( Vars),
							 | 
						||
| 
								 | 
							
									global_term_ref_1( Global),
							 | 
						||
| 
								 | 
							
									empty_history( History),
							 | 
						||
| 
								 | 
							
									create_mutable( active, Mref),
							 | 
						||
| 
								 | 
							
									create_mutable( 0, Gref),
							 | 
						||
| 
								 | 
							
									create_mutable( History, Href),
							 | 
						||
| 
								 | 
							
									gen_id( Id),
							 | 
						||
| 
								 | 
							
									Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args].
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- meta_predicate insert_constraint_internal(-,-,?,:,+,+).
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								insert_constraint_internal( [Global|Vars], Self, Term, Closure, F, Args) :-
							 | 
						||
| 
								 | 
							
									term_variables( Term, Vars),
							 | 
						||
| 
								 | 
							
									none_locked( Vars),
							 | 
						||
| 
								 | 
							
									global_term_ref_1( Global),
							 | 
						||
| 
								 | 
							
									empty_history( History),
							 | 
						||
| 
								 | 
							
									create_mutable( active, Mref),
							 | 
						||
| 
								 | 
							
									create_mutable( 0, Gref),
							 | 
						||
| 
								 | 
							
									create_mutable( History, Href),
							 | 
						||
| 
								 | 
							
									gen_id( Id),
							 | 
						||
| 
								 | 
							
									Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args].
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								gen_id( Id) :-
							 | 
						||
| 
								 | 
							
									incval( id, Id).
							 | 
						||
| 
								 | 
							
								        /* no undo/1 in sicstus3.7
							 | 
						||
| 
								 | 
							
									( Id =:= 1 ->				% first time called
							 | 
						||
| 
								 | 
							
									    undo( setval(id,0))
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    true
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
									*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Eager removal from all chains.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								remove_constraint_internal( Susp, Agenda) :-
							 | 
						||
| 
								 | 
							
									arg( 2, Susp, Mref),
							 | 
						||
| 
								 | 
							
									get_mutable( State, Mref),
							 | 
						||
| 
								 | 
							
									update_mutable( removed, Mref),		% mark in any case
							 | 
						||
| 
								 | 
							
									( compound(State) ->			% passive/1
							 | 
						||
| 
								 | 
							
									    Agenda = []
							 | 
						||
| 
								 | 
							
									; State==removed ->
							 | 
						||
| 
								 | 
							
									    Agenda = []
							 | 
						||
| 
								 | 
							
									; State==triggered ->
							 | 
						||
| 
								 | 
							
									    Agenda = []
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
								            Susp =.. [_,_,_,_,_,_,_|Args],
							 | 
						||
| 
								 | 
							
									    term_variables( Args, Vars),
							 | 
						||
| 
								 | 
							
									    global_term_ref_1( Global),
							 | 
						||
| 
								 | 
							
									    Agenda = [Global|Vars]
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Protect the goal against any binding
							 | 
						||
| 
								 | 
							
								% or attachment of constraints. The latter is
							 | 
						||
| 
								 | 
							
								% via the notify_constrained/1 convention.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								lock( T) :- var(T), put_atts( T, locked).
							 | 
						||
| 
								 | 
							
								lock( T) :- nonvar( T),
							 | 
						||
| 
								 | 
							
									functor( T, _, N),
							 | 
						||
| 
								 | 
							
									lock_arg( N, T).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								lock_arg( 0, _) :- !.
							 | 
						||
| 
								 | 
							
								lock_arg( 1, T) :- !, arg( 1, T, A), lock( A).
							 | 
						||
| 
								 | 
							
								lock_arg( 2, T) :- !, arg( 1, T, A), lock( A), arg( 2, T, B), lock( B).
							 | 
						||
| 
								 | 
							
								lock_arg( N, T) :-
							 | 
						||
| 
								 | 
							
									arg( N, T, A),
							 | 
						||
| 
								 | 
							
									lock( A),
							 | 
						||
| 
								 | 
							
									M is N-1,
							 | 
						||
| 
								 | 
							
									lock_arg( M, T).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								unlock( T) :- var(T), put_atts( T, -locked).
							 | 
						||
| 
								 | 
							
								unlock( T) :- nonvar( T),
							 | 
						||
| 
								 | 
							
									functor( T, _, N),
							 | 
						||
| 
								 | 
							
									unlock_arg( N, T).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								unlock_arg( 0, _) :- !.
							 | 
						||
| 
								 | 
							
								unlock_arg( 1, T) :- !, arg( 1, T, A), unlock( A).
							 | 
						||
| 
								 | 
							
								unlock_arg( 2, T) :- !, arg( 1, T, A), unlock( A), arg( 2, T, B), unlock( B).
							 | 
						||
| 
								 | 
							
								unlock_arg( N, T) :-
							 | 
						||
| 
								 | 
							
									arg( N, T, A),
							 | 
						||
| 
								 | 
							
									unlock( A),
							 | 
						||
| 
								 | 
							
									M is N-1,
							 | 
						||
| 
								 | 
							
									unlock_arg( M, T).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								verify_attributes( X, Y, []) :-
							 | 
						||
| 
								 | 
							
									get_atts( X, locked),
							 | 
						||
| 
								 | 
							
									!,
							 | 
						||
| 
								 | 
							
									var(Y),
							 | 
						||
| 
								 | 
							
									get_atts( Y, -locked),
							 | 
						||
| 
								 | 
							
									put_atts( Y,  locked).
							 | 
						||
| 
								 | 
							
								verify_attributes( _, _, []).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								none_locked( []).
							 | 
						||
| 
								 | 
							
								none_locked( [V|Vs]) :-
							 | 
						||
| 
								 | 
							
									not_locked( V),
							 | 
						||
| 
								 | 
							
									none_locked( Vs).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								not_locked( V) :- var( V), get_atts( V, -locked).
							 | 
						||
| 
								 | 
							
								not_locked( V) :- nonvar( V).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% -------------------------- access to constraints ------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Try a list of candidates. V may be nonvar but
							 | 
						||
| 
								 | 
							
								% bound to a term with variables in it.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								via( L, V) :-
							 | 
						||
| 
								 | 
							
									member( X, L),
							 | 
						||
| 
								 | 
							
									var( X),
							 | 
						||
| 
								 | 
							
									!,
							 | 
						||
| 
								 | 
							
									V = X.
							 | 
						||
| 
								 | 
							
								via( L, V) :-
							 | 
						||
| 
								 | 
							
									compound( L),
							 | 
						||
| 
								 | 
							
									nonground( L, V),
							 | 
						||
| 
								 | 
							
									!.
							 | 
						||
| 
								 | 
							
								via( _, V) :-
							 | 
						||
| 
								 | 
							
									global_term_ref_1( V).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% specialization(s)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								via_1( X, V) :- var(X), !, X=V.
							 | 
						||
| 
								 | 
							
								via_1( T, V) :- compound(T), nonground( T, V), !.
							 | 
						||
| 
								 | 
							
								via_1( _, V) :- global_term_ref_1( V).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								via_2( X, _, V) :- var(X), !, X=V.
							 | 
						||
| 
								 | 
							
								via_2( _, Y, V) :- var(Y), !, Y=V.
							 | 
						||
| 
								 | 
							
								via_2( T, _, V) :- compound(T), nonground( T, V), !.
							 | 
						||
| 
								 | 
							
								via_2( _, T, V) :- compound(T), nonground( T, V), !.
							 | 
						||
| 
								 | 
							
								via_2( _, _, V) :- global_term_ref_1( V).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								via_3( X, _, _, V) :- var(X), !, X=V.
							 | 
						||
| 
								 | 
							
								via_3( _, Y, _, V) :- var(Y), !, Y=V.
							 | 
						||
| 
								 | 
							
								via_3( _, _, Z, V) :- var(Z), !, Z=V.
							 | 
						||
| 
								 | 
							
								via_3( T, _, _, V) :- compound(T), nonground( T, V), !.
							 | 
						||
| 
								 | 
							
								via_3( _, T, _, V) :- compound(T), nonground( T, V), !.
							 | 
						||
| 
								 | 
							
								via_3( _, _, T, V) :- compound(T), nonground( T, V), !.
							 | 
						||
| 
								 | 
							
								via_3( _, _, _, V) :- global_term_ref_1( V).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% The second arg is a witness.
							 | 
						||
| 
								 | 
							
								% The formulation with term_variables/2 is
							 | 
						||
| 
								 | 
							
								% cycle safe, but it finds a list of all vars.
							 | 
						||
| 
								 | 
							
								% We need only one, and no list in particular.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								nonground( Term, V) :-
							 | 
						||
| 
								 | 
							
									term_variables( Term, Vs),
							 | 
						||
| 
								 | 
							
									Vs = [V|_].
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								nonground( Term, V) :- var( Term), V=Term.
							 | 
						||
| 
								 | 
							
								nonground( Term, V) :- compound( Term),
							 | 
						||
| 
								 | 
							
									functor( Term, _, N),
							 | 
						||
| 
								 | 
							
									nonground( N, Term, V).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% assert: N > 0
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								nonground( 1, Term, V) :- !,
							 | 
						||
| 
								 | 
							
									arg( 1, Term, Arg),
							 | 
						||
| 
								 | 
							
									nonground( Arg, V).
							 | 
						||
| 
								 | 
							
								nonground( 2, Term, V) :- !,
							 | 
						||
| 
								 | 
							
									arg( 2, Term, Arg2),
							 | 
						||
| 
								 | 
							
									( nonground( Arg2, V) ->
							 | 
						||
| 
								 | 
							
									    true
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    arg( 1, Term, Arg1),
							 | 
						||
| 
								 | 
							
									    nonground( Arg1, V)
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								nonground( N, Term, V) :-
							 | 
						||
| 
								 | 
							
									arg( N, Term, Arg),
							 | 
						||
| 
								 | 
							
									( nonground( Arg, V) ->
							 | 
						||
| 
								 | 
							
									    true
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    M is N-1,
							 | 
						||
| 
								 | 
							
									    nonground( M, Term, V)
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								constraint_generation( Susp, State, Generation) :-
							 | 
						||
| 
								 | 
							
									arg( 2, Susp, Mref),
							 | 
						||
| 
								 | 
							
									get_mutable( State, Mref),
							 | 
						||
| 
								 | 
							
									arg( 4, Susp, Gref),
							 | 
						||
| 
								 | 
							
									get_mutable( Generation, Gref). 	% not incremented meanwhile
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								change_state( Susp, State) :-
							 | 
						||
| 
								 | 
							
									arg( 2, Susp, Mref),
							 | 
						||
| 
								 | 
							
									update_mutable( State, Mref).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- meta_predicate expose(-,+,+,+,:).
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								expose_active( Ref, Head, Tid, Heads, Continuation) :-
							 | 
						||
| 
								 | 
							
									get_exposed( Ref),
							 | 
						||
| 
								 | 
							
									get_mutable( Exposed, Ref),
							 | 
						||
| 
								 | 
							
									update_mutable( [active(Head,Tid,Heads,Continuation)|Exposed], Ref).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								expose_passive( Ref, Heads) :-
							 | 
						||
| 
								 | 
							
									get_exposed( Ref),
							 | 
						||
| 
								 | 
							
									get_mutable( Exposed, Ref),
							 | 
						||
| 
								 | 
							
									update_mutable( [passive(Heads)|Exposed], Ref).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								de_expose( Ref) :-
							 | 
						||
| 
								 | 
							
									get_mutable( [_|Exposed], Ref),
							 | 
						||
| 
								 | 
							
									update_mutable( Exposed, Ref).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Prefer passive over active (cheaper to deal with).
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								is_exposed( Constraint, Suspension, Continuation) :-
							 | 
						||
| 
								 | 
							
									get_exposed( Ref),
							 | 
						||
| 
								 | 
							
									get_mutable( Exposed, Ref),
							 | 
						||
| 
								 | 
							
									is_exposed( Exposed, Constraint, Suspension, Continuation).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								is_exposed( [E|Es], Constraint, Suspension, Continuation) :-
							 | 
						||
| 
								 | 
							
									is_exposed( E, Constraint, Suspension, Continuation, Es).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								is_exposed( active(Head,Susp,Heads,Cont), Constraint, Suspension, Continuation, Es) :-
							 | 
						||
| 
								 | 
							
									( member( C#Suspension, Heads),
							 | 
						||
| 
								 | 
							
									  Constraint == C ->
							 | 
						||
| 
								 | 
							
									    Continuation = true
							 | 
						||
| 
								 | 
							
									; Constraint == Head ->
							 | 
						||
| 
								 | 
							
									    ( is_exposed( Es, Constraint, Suspension, true) -> % prefer
							 | 
						||
| 
								 | 
							
										Continuation = true
							 | 
						||
| 
								 | 
							
									    ;
							 | 
						||
| 
								 | 
							
										Continuation = Cont,
							 | 
						||
| 
								 | 
							
										Suspension = Susp
							 | 
						||
| 
								 | 
							
									    )
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    is_exposed( Es, Constraint, Suspension, Continuation)
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								is_exposed( passive(Heads), Constraint, Suspension, Continuation, Es) :-
							 | 
						||
| 
								 | 
							
									( member( C#Suspension, Heads),
							 | 
						||
| 
								 | 
							
									  Constraint == C ->
							 | 
						||
| 
								 | 
							
									    Continuation = true
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    is_exposed( Es, Constraint, Suspension, Continuation)
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								get_exposed( Ref) :-
							 | 
						||
| 
								 | 
							
									global_term_ref_1( Global),
							 | 
						||
| 
								 | 
							
									( get_atts( Global, exposed(Ref)) ->
							 | 
						||
| 
								 | 
							
									    true
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    create_mutable( [], Ref),
							 | 
						||
| 
								 | 
							
									    put_atts( Global, exposed(Ref))
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								get_dbg_state( Ref) :-
							 | 
						||
| 
								 | 
							
									global_term_ref_1( Global),
							 | 
						||
| 
								 | 
							
									( get_atts( Global, dbg_state(Ref)) ->
							 | 
						||
| 
								 | 
							
									    true
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    create_mutable( [], Ref),
							 | 
						||
| 
								 | 
							
									    put_atts( Global, dbg_state(Ref))
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% ------------------- abstract data type for propagation rules -------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								empty_history( E) :- empty_assoc( E).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% assert: constraints/tuples are comparable directly
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								novel_production( Self, Tuple) :-
							 | 
						||
| 
								 | 
							
									arg( 5, Self, Ref),
							 | 
						||
| 
								 | 
							
									get_mutable( History, Ref),
							 | 
						||
| 
								 | 
							
									( get_assoc( Tuple, History, _) ->
							 | 
						||
| 
								 | 
							
									    fail
							 | 
						||
| 
								 | 
							
									;
							 | 
						||
| 
								 | 
							
									    true
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Not folded with novel_production/2 because guard checking
							 | 
						||
| 
								 | 
							
								% goes in between the two calls.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								extend_history( Self, Tuple) :-
							 | 
						||
| 
								 | 
							
									arg( 5, Self, Ref),
							 | 
						||
| 
								 | 
							
									get_mutable( History, Ref),
							 | 
						||
| 
								 | 
							
									put_assoc( Tuple, History, x, NewHistory),
							 | 
						||
| 
								 | 
							
									update_mutable( NewHistory, Ref).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- load_foreign_resource(library(system(chr))).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								end_of_file.
							 | 
						||
| 
								 | 
							
								
							 |