%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  Constraint Handling Rules			      version 2.2 %
%								  %
%  (c) Copyright 1996-98					  %
%  LMU, Muenchen						  %
%								  %
%  File:   sbag_a.pl						  %
%  Author: Christian Holzbaur		christian@ai.univie.ac.at %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%
% bags of suspensions
%

:- module( sbag,
	[
	    iter_init/2,
	    iter_last/1,
	    iter_next/3,
	    list_to_sbag/2,
	    sbag_empty/1,
	    sbag_member/2,
	    sbag_union/3,
	    sbag_add_element/3,
	    sbag_del_element/3
	]).

:- use_module( library(assoc),
	[
	    assoc_to_list/2,
	    put_assoc/4,
	    del_assoc/4,
	    gen_assoc/3,
	    list_to_assoc/2,
	    ord_list_to_assoc/2
	]).

% -----------------------------------------------------------------
%
% *** MACROS ***
%
:- multifile
	user:goal_expansion/3.
:- dynamic
	user:goal_expansion/3.
%
user:goal_expansion( iter_init(A,B),	   _, sbag:down(A,[],B)).
user:goal_expansion( iter_last([]),	   _, true).
user:goal_expansion( iter_next([A|B],C,D), _, sbag:iter_next(A,B,D,C)).
user:goal_expansion( sbag_empty(A),        _, A==t).

% -----------------------------------------------------------------

iter_init( Assoc, Contin) :-
	down( Assoc, [], Contin).

iter_last( []).

sbag_empty( B) :- B == t.

%
% fails for empty
%
iter_next( [Node|Cont], Elem, Next) :-
	iter_next( Node, Cont, Next, Elem).

iter_next( t(K,_,_,_,R), Cont, Next, K) :-	% cf. assoc.pl
	down( R, Cont, Next).
/*
	( R==t,L==t -> Next=Cont
	; R==t ->      Next=Cont % Next=[t(K,V,0,t,t)|Cont]
	;	       down( R, Cont, Next)
	).
*/

down( t,    Ci, Ci).
down( Node, Ci, Co) :-
	Node = t(_,_,_,L,_),
	down( L, [Node|Ci], Co).

list_to_sbag( L, A) :-
	list_to_sbag( L, t, A).

list_to_sbag([],     Assoc, Assoc).
list_to_sbag([X|Xs], Assoc0, Assoc) :-
	put_assoc( X, Assoc0, 0, Assoc1),
	list_to_sbag( Xs, Assoc1, Assoc).

sbag_member( Elem, A) :-
	gen_assoc( Elem, A, _).

sbag_union( A, B, C) :-
	assoc_to_list( A, As),
	assoc_to_list( B, Bs),
	prolog:merge( As, Bs, Cs),
	ord_list_to_assoc( Cs, C).

sbag_add_element( S1, E, S2) :- put_assoc( E, S1, 0, S2).

sbag_del_element( S1, E, S2) :- del_assoc( E, S1, _, S2).


end_of_file.
% -----------------------------------------------------------------

test( N) :-
	length( L, N),
	list_to_assoc( L, A),
	down( A, [], C),
	a2l( C, L1),
	assoc_to_list( A, L2),
	( L1==L1 -> true ; raise_exception( mismatch(L1,L2))).

bug(L) :-
  A = t(c,0,0,t(b,0,-1,t(a,0,0,t,t),t),
	      t(e,0,0,t(d,0,0,t,t),
		      t(f,0,0,t,t))),
  iter_init( A, S),
  a2l( S, L).

a2l( S, []) :- iter_last( S).
a2l( S, [X|Xs]) :-
	iter_next( S, X, N),
	a2l( N, Xs).