purge duplicated content.
This commit is contained in:
		@@ -1,544 +0,0 @@
 | 
			
		||||
/*  $Id: aggregate.pl,v 1.4 2008-07-22 23:34:49 vsc Exp $
 | 
			
		||||
 | 
			
		||||
    Part of SWI-Prolog
 | 
			
		||||
 | 
			
		||||
    Author:        Jan Wielemaker
 | 
			
		||||
    E-mail:        wielemak@science.uva.nl
 | 
			
		||||
    WWW:           http://www.swi-prolog.org
 | 
			
		||||
    Copyright (C): 2008, University of Amsterdam
 | 
			
		||||
 | 
			
		||||
    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 General Public
 | 
			
		||||
    License along with this library; if not, write to the Free Software
 | 
			
		||||
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
:- module(aggretate,
 | 
			
		||||
	  [ foreach/2,			% :Generator, :Goal
 | 
			
		||||
	    aggregate/3,		% +Templ, :Goal, -Result
 | 
			
		||||
	    aggregate/4,		% +Templ, +Discrim, :Goal, -Result
 | 
			
		||||
	    aggregate_all/3,		% +Templ, :Goal, -Result
 | 
			
		||||
	    aggregate_all/4,		% +Templ, +Discrim, :Goal, -Result
 | 
			
		||||
	    free_variables/4		% :Generator, :Template, +Vars0, -Vars
 | 
			
		||||
	  ]).
 | 
			
		||||
:- use_module(library(ordsets)).
 | 
			
		||||
:- use_module(library(pairs)).
 | 
			
		||||
:- use_module(library(error)).
 | 
			
		||||
:- use_module(library(lists)).
 | 
			
		||||
 | 
			
		||||
:- meta_predicate
 | 
			
		||||
	foreach(0,0),
 | 
			
		||||
	aggregate(?,0,-),
 | 
			
		||||
	aggregate(?,?,0,-),
 | 
			
		||||
	aggregate_all(?,0,-),
 | 
			
		||||
	aggregate_all(?,?,0,-).
 | 
			
		||||
 | 
			
		||||
/** <module> Aggregation operators on backtrackable predicates
 | 
			
		||||
 | 
			
		||||
This library provides aggregating operators  over   the  solutions  of a
 | 
			
		||||
predicate. The operations are a generalisation   of the bagof/3, setof/3
 | 
			
		||||
and findall/3 built-in predicates. The   defined  aggregation operations
 | 
			
		||||
are counting, computing the sum, minimum,   maximum,  a bag of solutions
 | 
			
		||||
and a set of solutions. We first   give  a simple example, computing the
 | 
			
		||||
country with the smallest area:
 | 
			
		||||
 | 
			
		||||
==
 | 
			
		||||
average_country_area(Name, Area) :-
 | 
			
		||||
	aggregate(min(A, N), country(N, A), min(Area, Name)).
 | 
			
		||||
==
 | 
			
		||||
 | 
			
		||||
There are four aggregation predicates, distinguished on two properties.
 | 
			
		||||
 | 
			
		||||
    $ aggregate vs. aggregate_all :
 | 
			
		||||
    The aggregate predicates use setof/3 (aggregate/4) or bagof/3
 | 
			
		||||
    (aggregate/3), dealing with existential qualified variables
 | 
			
		||||
    (Var^Goal) and providing multiple solutions for the remaining free
 | 
			
		||||
    variables in Goal. The aggregate_all/3 predicate uses findall/3,
 | 
			
		||||
    implicitely qualifying all free variables and providing exactly one
 | 
			
		||||
    solution, while aggregate_all/4 uses sort/2 over solutions and
 | 
			
		||||
    Distinguish (see below) generated using findall/3.
 | 
			
		||||
 | 
			
		||||
    $ The Distinguish argument :
 | 
			
		||||
    The versions with 4 arguments provide a Distinguish argument that
 | 
			
		||||
    allow for keeping duplicate bindings of a variable in the result.
 | 
			
		||||
    For example, if we wish to compute the total population of all
 | 
			
		||||
    countries we do not want to loose results because two countries
 | 
			
		||||
    have the same population.  Therefore we use:
 | 
			
		||||
    
 | 
			
		||||
    ==
 | 
			
		||||
	aggregate(sum(P), Name, country(Name, P), Total)
 | 
			
		||||
    ==
 | 
			
		||||
 | 
			
		||||
All aggregation predicates support the following operator below in
 | 
			
		||||
Template. In addition, they allow for an arbitrary named compound term
 | 
			
		||||
where each of the arguments is a term from the list below. I.e. the term
 | 
			
		||||
r(min(X), max(X)) computes both the minimum and maximum binding for X.
 | 
			
		||||
 | 
			
		||||
	* count
 | 
			
		||||
	Count number of solutions.  Same as sum(1).
 | 
			
		||||
	* sum(Expr)
 | 
			
		||||
	Sum of Expr for all solutions.
 | 
			
		||||
	* min(Expr)
 | 
			
		||||
	Minimum of Expr for all solutions.
 | 
			
		||||
	* min(Expr, Witness)
 | 
			
		||||
	A term min(Min, Witness), where Min is the minimal version
 | 
			
		||||
	of Expr over all Solution and Witness is any other template
 | 
			
		||||
	the applied to the solution that produced Min.  If multiple
 | 
			
		||||
	solutions provide the same minimum, Witness corresponds to
 | 
			
		||||
	the first solution.
 | 
			
		||||
	* max(Expr)
 | 
			
		||||
	Maximum of Expr for all solutions.
 | 
			
		||||
	* max(Expr, Witness)
 | 
			
		||||
	As min(Expr, Witness), but producing the maximum result.
 | 
			
		||||
	* set(X)
 | 
			
		||||
	An ordered set with all solutions for X.
 | 
			
		||||
	* bag(X)
 | 
			
		||||
	A list of all solutions for X.
 | 
			
		||||
 | 
			
		||||
---+++ Acknowledgements
 | 
			
		||||
 | 
			
		||||
_|The development of this library was sponsored by SecuritEase,
 | 
			
		||||
  http://www.securitease.com
 | 
			
		||||
|_
 | 
			
		||||
 | 
			
		||||
@compat Quintus, SICStus 4. The forall/2 is a SWI-Prolog built-in and
 | 
			
		||||
	term_variables/3 is a SWI-Prolog with a *|different definition|*.
 | 
			
		||||
@tbd	Analysing the aggregation template and compiling a predicate
 | 
			
		||||
	for the list aggregation can be done at compile time.
 | 
			
		||||
@tbd	aggregate_all/3 can be rewritten to run in constant space using
 | 
			
		||||
	non-backtrackable assignment on a term.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
		 /*******************************
 | 
			
		||||
		 *	     AGGREGATE		*
 | 
			
		||||
		 *******************************/
 | 
			
		||||
 | 
			
		||||
%%	aggregate(+Template, :Goal, -Result) is nondet.
 | 
			
		||||
%
 | 
			
		||||
%	Aggregate bindings in Goal according to Template.  The aggregate/3
 | 
			
		||||
%	version performs bagof/3 on Goal.
 | 
			
		||||
 | 
			
		||||
aggregate(Template, Goal0, Result) :-
 | 
			
		||||
	template_to_pattern(bag, Template, Pattern, Goal0, Goal, Aggregate),
 | 
			
		||||
	bagof(Pattern, Goal, List),
 | 
			
		||||
	aggregate_list(Aggregate, List, Result).
 | 
			
		||||
 | 
			
		||||
%%	aggregate(+Template, +Discriminator, :Goal, -Result) is nondet.
 | 
			
		||||
%
 | 
			
		||||
%	Aggregate bindings in Goal according to Template.  The aggregate/3
 | 
			
		||||
%	version performs setof/3 on Goal.
 | 
			
		||||
 | 
			
		||||
aggregate(Template, Discriminator, Goal0, Result) :-
 | 
			
		||||
	template_to_pattern(bag, Template, Pattern, Goal0, Goal, Aggregate),
 | 
			
		||||
	setof(Discriminator-Pattern, Goal, Pairs),
 | 
			
		||||
	pairs_values(Pairs, List),
 | 
			
		||||
	aggregate_list(Aggregate, List, Result).
 | 
			
		||||
 | 
			
		||||
%%	aggregate_all(+Template, :Goal, -Result) is semidet.
 | 
			
		||||
%
 | 
			
		||||
%	Aggregate bindings in Goal according to Template.  The aggregate_all/3
 | 
			
		||||
%	version performs findall/3 on Goal.
 | 
			
		||||
 | 
			
		||||
aggregate_all(Template, Goal0, Result) :-
 | 
			
		||||
	template_to_pattern(all, Template, Pattern, Goal0, Goal, Aggregate),
 | 
			
		||||
	findall(Pattern, Goal, List),
 | 
			
		||||
	aggregate_list(Aggregate, List, Result).
 | 
			
		||||
 | 
			
		||||
%%	aggregate_all(+Template, +Discriminator, :Goal, -Result) is semidet.
 | 
			
		||||
%
 | 
			
		||||
%	Aggregate bindings in Goal according to Template.  The aggregate_all/3
 | 
			
		||||
%	version performs findall/3 followed by sort/2 on Goal.
 | 
			
		||||
 | 
			
		||||
aggregate_all(Template, Discriminator, Goal0, Result) :-
 | 
			
		||||
	template_to_pattern(all, Template, Pattern, Goal0, Goal, Aggregate),
 | 
			
		||||
	findall(Discriminator-Pattern, Goal, Pairs0),
 | 
			
		||||
	sort(Pairs0, Pairs),
 | 
			
		||||
	pairs_values(Pairs, List),
 | 
			
		||||
	aggregate_list(Aggregate, List, Result).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template_to_pattern(_All, Template, Pattern, Goal0, Goal, Aggregate) :-
 | 
			
		||||
	template_to_pattern(Template, Pattern, Post, Vars, Aggregate),
 | 
			
		||||
	existential_vars(Goal0, Goal1, AllVars, Vars),
 | 
			
		||||
	clean_body((Goal1, Post), Goal2),
 | 
			
		||||
	add_existential_vars(AllVars, Goal2, Goal).
 | 
			
		||||
 | 
			
		||||
existential_vars(Var, Var) -->
 | 
			
		||||
	{ var(Var) }, !.
 | 
			
		||||
existential_vars(Var^G0, G) --> !,
 | 
			
		||||
	[Var],
 | 
			
		||||
	existential_vars(G0, G).
 | 
			
		||||
existential_vars(G, G) -->
 | 
			
		||||
	[].
 | 
			
		||||
 | 
			
		||||
add_existential_vars([], G, G).
 | 
			
		||||
add_existential_vars([H|T], G0, H^G1) :-
 | 
			
		||||
	add_existential_vars(T, G0, G1).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%%	clean_body(+Goal0, -Goal) is det.
 | 
			
		||||
%
 | 
			
		||||
%	Remove redundant =true= from Goal0.
 | 
			
		||||
 | 
			
		||||
clean_body((Goal0,Goal1), Goal) :- !,
 | 
			
		||||
	clean_body(Goal0, GoalA),
 | 
			
		||||
	clean_body(Goal1, GoalB),
 | 
			
		||||
	(   GoalA == true
 | 
			
		||||
	->  Goal = GoalB
 | 
			
		||||
	;   GoalB == true
 | 
			
		||||
	->  Goal = GoalA
 | 
			
		||||
	;   Goal = (GoalA,GoalB)
 | 
			
		||||
	).
 | 
			
		||||
clean_body(Goal, Goal).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%%	template_to_pattern(+Template, -Pattern, -Post, -Vars, -Agregate)
 | 
			
		||||
%
 | 
			
		||||
%	Determine which parts of the goal we must remember in the
 | 
			
		||||
%	findall/3 pattern.
 | 
			
		||||
%	
 | 
			
		||||
%	@param Post is a body-term that evaluates expressions to reduce
 | 
			
		||||
%		    storage requirements.
 | 
			
		||||
%	@param Vars is a list of intermediate variables that must be
 | 
			
		||||
%		    added to the existential variables for bagof/3.
 | 
			
		||||
%	@param Agregate defines the aggregation operation to execute. 
 | 
			
		||||
 | 
			
		||||
template_to_pattern(sum(X),	      X,	 true, 	  [],   sum) :- var(X), !.
 | 
			
		||||
template_to_pattern(sum(X0),	      X,	 X is X0, [X0], sum) :- !.
 | 
			
		||||
template_to_pattern(count,	      1,	 true,    [],   count) :- !.
 | 
			
		||||
template_to_pattern(min(X),	      X,	 true,    [],   min) :- var(X), !.
 | 
			
		||||
template_to_pattern(min(X0),	      X,	 X is X0, [X0], min) :- !.
 | 
			
		||||
template_to_pattern(min(X0, Witness), X-Witness, X is X0, [X0], min_witness) :- !.
 | 
			
		||||
template_to_pattern(max(X0),	      X,	 X is X0, [X0], max) :- !.
 | 
			
		||||
template_to_pattern(max(X0, Witness), X-Witness, X is X0, [X0], max_witness) :- !.
 | 
			
		||||
template_to_pattern(set(X),	      X,	 true,    [],   set) :- !.
 | 
			
		||||
template_to_pattern(bag(X),	      X,	 true,    [],   bag) :- !.
 | 
			
		||||
template_to_pattern(Term, Pattern, Goal, Vars, term(MinNeeded, Functor, AggregateArgs)) :-
 | 
			
		||||
	compound(Term), !,
 | 
			
		||||
	Term =.. [Functor|Args0],
 | 
			
		||||
	templates_to_patterns(Args0, Args, Goal, Vars, AggregateArgs),
 | 
			
		||||
	needs_one(AggregateArgs, MinNeeded),
 | 
			
		||||
	Pattern =.. [Functor|Args].
 | 
			
		||||
template_to_pattern(Term, _, _, _, _) :-
 | 
			
		||||
	type_error(aggregate_template, Term).
 | 
			
		||||
 | 
			
		||||
templates_to_patterns([], [], true, [], []).
 | 
			
		||||
templates_to_patterns([H0], [H], G, Vars, [A]) :- !,
 | 
			
		||||
	template_to_pattern(H0, H, G, Vars, A).
 | 
			
		||||
templates_to_patterns([H0|T0], [H|T], (G0,G), Vars, [A0|A]) :-
 | 
			
		||||
	template_to_pattern(H0, H, G0, V0, A0),
 | 
			
		||||
	append(V0, RV, Vars),
 | 
			
		||||
	templates_to_patterns(T0, T, G, RV, A).
 | 
			
		||||
			    
 | 
			
		||||
%%	needs_one(+Ops, -OneOrZero)
 | 
			
		||||
%
 | 
			
		||||
%	If one of the operations in Ops needs at least one answer,
 | 
			
		||||
%	unify OneOrZero to 1.  Else 0.
 | 
			
		||||
 | 
			
		||||
needs_one(Ops, 1) :-
 | 
			
		||||
	member(Op, Ops),
 | 
			
		||||
	needs_one(Op), !.
 | 
			
		||||
needs_one(_, 0).
 | 
			
		||||
 | 
			
		||||
needs_one(min).
 | 
			
		||||
needs_one(min_witness).
 | 
			
		||||
needs_one(max).
 | 
			
		||||
needs_one(max_witness).
 | 
			
		||||
 | 
			
		||||
%%	aggregate_list(+Op, +List, -Answer) is semidet.
 | 
			
		||||
%
 | 
			
		||||
%	Aggregate the answer  from  the   list  produced  by  findall/3,
 | 
			
		||||
%	bagof/3 or setof/3. The latter  two   cases  deal  with compound
 | 
			
		||||
%	answers.
 | 
			
		||||
%	
 | 
			
		||||
%	@tbd	Compile code for incremental state update, which we will use
 | 
			
		||||
%		for aggregate_all/3 as well.  We should be using goal_expansion
 | 
			
		||||
%		to generate these clauses.
 | 
			
		||||
 | 
			
		||||
aggregate_list(bag, List0, List) :- !,
 | 
			
		||||
	List = List0.
 | 
			
		||||
aggregate_list(set, List, Set) :- !,
 | 
			
		||||
	sort(List, Set).
 | 
			
		||||
aggregate_list(sum, List, Sum) :-
 | 
			
		||||
	sumlist(List, Sum).
 | 
			
		||||
aggregate_list(count, List, Count) :-
 | 
			
		||||
	length(List, Count).
 | 
			
		||||
aggregate_list(max, List, Sum) :-
 | 
			
		||||
	max_list(List, Sum).
 | 
			
		||||
aggregate_list(max_witness, List, max(Max, Witness)) :-
 | 
			
		||||
	max_pair(List, Max, Witness).
 | 
			
		||||
aggregate_list(min, List, Sum) :-
 | 
			
		||||
	min_list(List, Sum).
 | 
			
		||||
aggregate_list(min_witness, List, min(Min, Witness)) :-
 | 
			
		||||
	min_pair(List, Min, Witness).
 | 
			
		||||
aggregate_list(term(0, Functor, Ops), List, Result) :- !,
 | 
			
		||||
	maplist(state0, Ops, StateArgs, FinishArgs),
 | 
			
		||||
	State0 =.. [Functor|StateArgs],
 | 
			
		||||
	aggregate_term_list(List, Ops, State0, Result0),
 | 
			
		||||
	finish_result(Ops, FinishArgs, Result0, Result).
 | 
			
		||||
aggregate_list(term(1, Functor, Ops), [H|List], Result) :-
 | 
			
		||||
	H =.. [Functor|Args],
 | 
			
		||||
	maplist(state1, Ops, Args, StateArgs, FinishArgs),
 | 
			
		||||
	State0 =.. [Functor|StateArgs],
 | 
			
		||||
	aggregate_term_list(List, Ops, State0, Result0),
 | 
			
		||||
	finish_result(Ops, FinishArgs, Result0, Result).
 | 
			
		||||
 | 
			
		||||
aggregate_term_list([], _, State, State).
 | 
			
		||||
aggregate_term_list([H|T], Ops, State0, State) :-
 | 
			
		||||
	step_term(Ops, H, State0, State1),
 | 
			
		||||
	aggregate_term_list(T, Ops, State1, State).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%%	min_pair(+Pairs, -Key, -Value) is det.
 | 
			
		||||
%%	max_pair(+Pairs, -Key, -Value) is det.
 | 
			
		||||
%
 | 
			
		||||
%	True if Key-Value has the  smallest/largest   key  in  Pairs. If
 | 
			
		||||
%	multiple pairs share the smallest/largest key, the first pair is
 | 
			
		||||
%	returned.
 | 
			
		||||
 | 
			
		||||
min_pair([M0-W0|T], M, W) :-
 | 
			
		||||
	min_pair(T, M0, W0, M, W).
 | 
			
		||||
 | 
			
		||||
min_pair([], M, W, M, W).
 | 
			
		||||
min_pair([M0-W0|T], M1, W1, M, W) :-
 | 
			
		||||
	(   M0 > M1
 | 
			
		||||
	->  min_pair(T, M0, W0, M, W)
 | 
			
		||||
	;   min_pair(T, M1, W1, M, W)
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
max_pair([M0-W0|T], M, W) :-
 | 
			
		||||
	max_pair(T, M0, W0, M, W).
 | 
			
		||||
 | 
			
		||||
max_pair([], M, W, M, W).
 | 
			
		||||
max_pair([M0-W0|T], M1, W1, M, W) :-
 | 
			
		||||
	(   M0 > M1
 | 
			
		||||
	->  max_pair(T, M0, W0, M, W)
 | 
			
		||||
	;   max_pair(T, M1, W1, M, W)
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
%%	step(+AggregateAction, +New, +State0, -State1).
 | 
			
		||||
 | 
			
		||||
step(bag,   X, [X|L], L).
 | 
			
		||||
step(set,   X, [X|L], L).
 | 
			
		||||
step(count, _, X0, X1) :-
 | 
			
		||||
	succ(X0, X1).
 | 
			
		||||
step(sum,   X, X0, X1) :-
 | 
			
		||||
	X1 is X0+X.
 | 
			
		||||
step(max,   X, X0, X1) :-
 | 
			
		||||
	X1 is max(X0, X).
 | 
			
		||||
step(min,   X, X0, X1) :-
 | 
			
		||||
	X1 is min(X0, X).
 | 
			
		||||
step(max_witness, X-W, X0-W0, X1-W1) :-
 | 
			
		||||
	(   X > X0
 | 
			
		||||
	->  X1 = X, W1 = W
 | 
			
		||||
	;   X1 = X0, W1 = W0
 | 
			
		||||
	).
 | 
			
		||||
step(min_witness, X-W, X0-W0, X1-W1) :-
 | 
			
		||||
	(   X < X0
 | 
			
		||||
	->  X1 = X, W1 = W
 | 
			
		||||
	;   X1 = X0, W1 = W0
 | 
			
		||||
	).
 | 
			
		||||
step(term(Ops), Row, Row0, Row1) :-
 | 
			
		||||
	step_term(Ops, Row, Row0, Row1).
 | 
			
		||||
 | 
			
		||||
step_term(Ops, Row, Row0, Row1) :-
 | 
			
		||||
	functor(Row, Name, Arity),
 | 
			
		||||
	functor(Row1, Name, Arity),
 | 
			
		||||
	step_list(Ops, 1, Row, Row0, Row1).
 | 
			
		||||
 | 
			
		||||
step_list([], _, _, _, _).
 | 
			
		||||
step_list([Op|OpT], Arg, Row, Row0, Row1) :-
 | 
			
		||||
	arg(Arg, Row, X),
 | 
			
		||||
	arg(Arg, Row0, X0),
 | 
			
		||||
	arg(Arg, Row1, X1),
 | 
			
		||||
	step(Op, X, X0, X1),
 | 
			
		||||
	succ(Arg, Arg1),
 | 
			
		||||
	step_list(OpT, Arg1, Row, Row0, Row1).
 | 
			
		||||
 | 
			
		||||
finish_result(Ops, Finish, R0, R) :-
 | 
			
		||||
	functor(R0, Functor, Arity),
 | 
			
		||||
	functor(R, Functor, Arity),
 | 
			
		||||
	finish_result(Ops, Finish, 1, R0, R).
 | 
			
		||||
 | 
			
		||||
finish_result([], _, _, _, _).
 | 
			
		||||
finish_result([Op|OpT], [F|FT], I, R0, R) :-
 | 
			
		||||
	arg(I, R0, A0),
 | 
			
		||||
	arg(I, R, A),
 | 
			
		||||
	finish_result1(Op, F, A0, A),
 | 
			
		||||
	succ(I, I2),
 | 
			
		||||
	finish_result(OpT, FT, I2, R0, R).
 | 
			
		||||
	
 | 
			
		||||
finish_result1(bag, Bag0, [], Bag) :- !,
 | 
			
		||||
	Bag = Bag0.
 | 
			
		||||
finish_result1(set, Bag,  [], Set) :- !,
 | 
			
		||||
	sort(Bag, Set).
 | 
			
		||||
finish_result1(max_witness, _, M-W, R) :- !,
 | 
			
		||||
	R = max(M,W).
 | 
			
		||||
finish_result1(min_witness, _, M-W, R) :- !,
 | 
			
		||||
	R = min(M,W).
 | 
			
		||||
finish_result1(_, _, A, A).
 | 
			
		||||
 | 
			
		||||
%%	state0(+Op, -State, -Finish)
 | 
			
		||||
 | 
			
		||||
state0(bag,   L, L).
 | 
			
		||||
state0(set,   L, L).
 | 
			
		||||
state0(count, 0, _).
 | 
			
		||||
state0(sum,   0, _).
 | 
			
		||||
 | 
			
		||||
%%	state1(+Op, +First, -State, -Finish)
 | 
			
		||||
 | 
			
		||||
state1(bag, X, [X|L], L).
 | 
			
		||||
state1(set, X, [X|L], L).
 | 
			
		||||
state1(_,   X, X,     _).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		 /*******************************
 | 
			
		||||
		 *	       FOREACH		*
 | 
			
		||||
		 *******************************/
 | 
			
		||||
 | 
			
		||||
%%	foreach(:Generator, :Goal)
 | 
			
		||||
%
 | 
			
		||||
%	True if the conjunction of instances  of Goal using the bindings
 | 
			
		||||
%	from  Generator  is  true.  Unlike    forall/2,   which  runs  a
 | 
			
		||||
%	failure-driven loop that  proves  Goal   for  each  solution  of
 | 
			
		||||
%	Generator, foreach creates a  conjunction.   Each  member of the
 | 
			
		||||
%	conjunction is a copy of  Goal,   where  the variables it shares
 | 
			
		||||
%	with Generator are filled with the values from the corresponding
 | 
			
		||||
%	solution.
 | 
			
		||||
%	
 | 
			
		||||
%	The implementation executes forall/2 if   Goal  does not contain
 | 
			
		||||
%	any variables that are not shared with Generator.
 | 
			
		||||
%	
 | 
			
		||||
%	Here is an example:
 | 
			
		||||
%	
 | 
			
		||||
%	==
 | 
			
		||||
%	?- foreach(between(1,4,X), dif(X,Y)), Y = 5.
 | 
			
		||||
%	Y = 5
 | 
			
		||||
%	?- foreach(between(1,4,X), dif(X,Y)), Y = 3.
 | 
			
		||||
%	No
 | 
			
		||||
%	==
 | 
			
		||||
%	
 | 
			
		||||
%	@bug	Goal is copied repeatetly, which may cause problems if
 | 
			
		||||
%		attributed variables are involved.
 | 
			
		||||
 | 
			
		||||
foreach(Generator, Goal0) :-
 | 
			
		||||
	strip_module(Goal0, M, G),
 | 
			
		||||
	Goal = M:G,
 | 
			
		||||
	term_variables(Generator, GenVars0), sort(GenVars0, GenVars),
 | 
			
		||||
	term_variables(Goal, GoalVars0), sort(GoalVars0, GoalVars),
 | 
			
		||||
	ord_subtract(GoalVars, GenVars, SharedGoalVars),
 | 
			
		||||
	(   SharedGoalVars == []
 | 
			
		||||
	->  \+ (Generator, \+Goal)	% = forall(Generator, Goal)
 | 
			
		||||
	;   ord_intersection(GenVars, GoalVars, SharedVars),
 | 
			
		||||
	    Templ =.. [v|SharedVars],
 | 
			
		||||
	    SharedTempl =.. [v|SharedGoalVars],
 | 
			
		||||
	    findall(Templ, Generator, List),
 | 
			
		||||
	    prove_list(List, Templ, SharedTempl, Goal)
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
prove_list([], _, _, _).
 | 
			
		||||
prove_list([H|T], Templ, SharedTempl, Goal) :-
 | 
			
		||||
	copy_term(Templ+SharedTempl+Goal,
 | 
			
		||||
		  H+SharedTempl+Copy),
 | 
			
		||||
	Copy,
 | 
			
		||||
	prove_list(T, Templ, SharedTempl, Goal).
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
%%	free_variables(:Generator, +Template, +VarList0, -VarList) is det.
 | 
			
		||||
%
 | 
			
		||||
%	In order to handle variables properly, we   have to find all the
 | 
			
		||||
%	universally quantified variables in the Generator. All variables
 | 
			
		||||
%	as yet unbound are universally quantified, unless
 | 
			
		||||
%   
 | 
			
		||||
%	    1. they occur in the template
 | 
			
		||||
%	    2. they are bound by X^P, setof, or bagof
 | 
			
		||||
%	
 | 
			
		||||
%	free_variables(Generator, Template, OldList, NewList) finds this
 | 
			
		||||
%	set, using OldList as an accumulator.
 | 
			
		||||
%	
 | 
			
		||||
%	@author Richard O'Keefe
 | 
			
		||||
%	@author Jan Wielemaker (made some SWI-Prolog enhancements)
 | 
			
		||||
%	@license Public domain (from DEC10 library).
 | 
			
		||||
%	@tbd Distinguish between control-structures and data terms.
 | 
			
		||||
%	@tbd Exploit our built-in term_variables/2 at some places?
 | 
			
		||||
 | 
			
		||||
free_variables(Term, Bound, VarList, [Term|VarList]) :-
 | 
			
		||||
	var(Term),
 | 
			
		||||
	term_is_free_of(Bound, Term),
 | 
			
		||||
	list_is_free_of(VarList, Term), !.
 | 
			
		||||
free_variables(Term, _Bound, VarList, VarList) :-
 | 
			
		||||
	var(Term), !.
 | 
			
		||||
free_variables(Term, Bound, OldList, NewList) :-
 | 
			
		||||
	explicit_binding(Term, Bound, NewTerm, NewBound), !,
 | 
			
		||||
	free_variables(NewTerm, NewBound, OldList, NewList).
 | 
			
		||||
free_variables(Term, Bound, OldList, NewList) :-
 | 
			
		||||
	functor(Term, _, N),
 | 
			
		||||
	free_variables(N, Term, Bound, OldList, NewList).
 | 
			
		||||
 | 
			
		||||
free_variables(0, _, _, VarList, VarList) :- !.
 | 
			
		||||
free_variables(N, Term, Bound, OldList, NewList) :-
 | 
			
		||||
	arg(N, Term, Argument),
 | 
			
		||||
	free_variables(Argument, Bound, OldList, MidList),
 | 
			
		||||
	M is N-1, !,
 | 
			
		||||
	free_variables(M, Term, Bound, MidList, NewList).
 | 
			
		||||
 | 
			
		||||
%   explicit_binding checks for goals known to existentially quantify
 | 
			
		||||
%   one or more variables.  In particular \+ is quite common.
 | 
			
		||||
 | 
			
		||||
explicit_binding(\+ _Goal,	       Bound, fail,	Bound      ) :- !.
 | 
			
		||||
explicit_binding(not(_Goal),	       Bound, fail,	Bound	   ) :- !.
 | 
			
		||||
explicit_binding(Var^Goal,	       Bound, Goal,	Bound+Var) :- !.
 | 
			
		||||
explicit_binding(setof(Var,Goal,Set),  Bound, Goal-Set, Bound+Var) :- !.
 | 
			
		||||
explicit_binding(bagof(Var,Goal,Bag),  Bound, Goal-Bag, Bound+Var) :- !.
 | 
			
		||||
 | 
			
		||||
%%	term_is_free_of(+Term, +Var) is semidet.
 | 
			
		||||
%
 | 
			
		||||
%	True if Var does not appear  in   Term.  This has been rewritten
 | 
			
		||||
%	from the DEC10 library source   to exploit our non-deterministic
 | 
			
		||||
%	arg/3.
 | 
			
		||||
 | 
			
		||||
term_is_free_of(Term, Var) :-
 | 
			
		||||
	\+ var_in_term(Term, Var).
 | 
			
		||||
 | 
			
		||||
var_in_term(Term, Var) :-
 | 
			
		||||
	Var == Term, !.
 | 
			
		||||
var_in_term(Term, Var) :-
 | 
			
		||||
	compound(Term),
 | 
			
		||||
	genarg(_, Term, Arg),
 | 
			
		||||
	var_in_term(Arg, Var), !.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%%	list_is_free_of(+List, +Var) is semidet.
 | 
			
		||||
%
 | 
			
		||||
%	True if Var is not in List.
 | 
			
		||||
 | 
			
		||||
list_is_free_of([Head|Tail], Var) :-
 | 
			
		||||
	Head \== Var, !,
 | 
			
		||||
	list_is_free_of(Tail, Var).
 | 
			
		||||
list_is_free_of([], _).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%	term_variables(+Term, +Vars0, -Vars) is det.
 | 
			
		||||
%
 | 
			
		||||
%	True if Vars is the union of variables in Term and Vars0.
 | 
			
		||||
%	We cannot have this as term_variables/3 is already defined
 | 
			
		||||
%	as a difference-list version of term_variables/2.
 | 
			
		||||
 | 
			
		||||
%term_variables(Term, Vars0, Vars) :-
 | 
			
		||||
%	term_variables(Term+Vars0, Vars).
 | 
			
		||||
@@ -1,89 +0,0 @@
 | 
			
		||||
/*  $Id$
 | 
			
		||||
 | 
			
		||||
    Part of SWI-Prolog
 | 
			
		||||
 | 
			
		||||
    Author:        Tom Schrijvers
 | 
			
		||||
    E-mail:        tom.schrijvers@cs.kuleuven.ac.be
 | 
			
		||||
    WWW:           http://www.swi-prolog.org
 | 
			
		||||
    Copyright (C): 2005, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | 
			
		||||
%
 | 
			
		||||
% Module for managing constraint solver events.
 | 
			
		||||
%
 | 
			
		||||
% Author: 	Tom Schrijvers
 | 
			
		||||
% E-mail: 	tom.schrijvers@cs.kuleuven.ac.be
 | 
			
		||||
% Copyright:	2005, K.U.Leuven
 | 
			
		||||
%
 | 
			
		||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | 
			
		||||
:-module(clp_events,
 | 
			
		||||
	[
 | 
			
		||||
		notify/2,
 | 
			
		||||
		subscribe/4,
 | 
			
		||||
		unsubscribe/2
 | 
			
		||||
	]).
 | 
			
		||||
 | 
			
		||||
notify(V,NMod) :-
 | 
			
		||||
	( get_attr(V,clp_events,List) ->
 | 
			
		||||
		notify_list(List,NMod)
 | 
			
		||||
	;
 | 
			
		||||
		true
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
subscribe(V,NMod,SMod,Goal) :-
 | 
			
		||||
	( get_attr(V,clp_events,List) ->
 | 
			
		||||
		put_attr(V,clp_events,[entry(NMod,SMod,Goal)|List])
 | 
			
		||||
	;
 | 
			
		||||
	        put_attr(V,clp_events,[entry(NMod,SMod,Goal)])
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
unsubscribe(V,SMod) :-
 | 
			
		||||
	( get_attr(V,clp_events,List) ->
 | 
			
		||||
		unsubscribe_list(List,SMod,NList),
 | 
			
		||||
		put_attr(V,clp_events,NList)
 | 
			
		||||
	;
 | 
			
		||||
		true
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
notify_list([],_).
 | 
			
		||||
notify_list([entry(Mod,_,Goal)|Rest],NMod) :-
 | 
			
		||||
	( Mod == NMod ->
 | 
			
		||||
		call(Goal)
 | 
			
		||||
	;
 | 
			
		||||
		true
 | 
			
		||||
	),
 | 
			
		||||
	notify_list(Rest,NMod).
 | 
			
		||||
 | 
			
		||||
unsubscribe_list([],_,_).
 | 
			
		||||
unsubscribe_list([Entry|Rest],SMod,List) :-
 | 
			
		||||
	Entry = entry(_,Mod,_),
 | 
			
		||||
	( Mod == SMod ->
 | 
			
		||||
		List = Rest
 | 
			
		||||
	;
 | 
			
		||||
		List = [Entry|Tail],
 | 
			
		||||
		unsubscribe_list(Rest,SMod,Tail)
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
attr_unify_hook(_,_).
 | 
			
		||||
@@ -1,141 +0,0 @@
 | 
			
		||||
/*  $Id: occurs.yap,v 1.1 2008-02-12 17:03:52 vsc Exp $
 | 
			
		||||
 | 
			
		||||
    Part of SWI-Prolog
 | 
			
		||||
 | 
			
		||||
    Author:        Jan Wielemaker
 | 
			
		||||
    E-mail:        jan@swi.psy.uva.nl
 | 
			
		||||
    WWW:           http://www.swi-prolog.org
 | 
			
		||||
    Copyright (C): 1985-2002, University of Amsterdam
 | 
			
		||||
 | 
			
		||||
    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
:- module(occurs,
 | 
			
		||||
	  [ contains_term/2,		% +SubTerm, +Term
 | 
			
		||||
	    contains_var/2,		% +SubTerm, +Term
 | 
			
		||||
	    free_of_term/2,		% +SubTerm, +Term
 | 
			
		||||
	    free_of_var/2,		% +SubTerm, +Term
 | 
			
		||||
	    occurrences_of_term/3,	% +SubTerm, +Term, ?Tally
 | 
			
		||||
	    occurrences_of_var/3,	% +SubTerm, +Term, ?Tally
 | 
			
		||||
	    sub_term/2,			% -SubTerm, +Term
 | 
			
		||||
	    sub_var/2			% -SubTerm, +Term (SWI extra)
 | 
			
		||||
	  ]).
 | 
			
		||||
 | 
			
		||||
:- use_module(library(arg),
 | 
			
		||||
	      [genarg/3]).
 | 
			
		||||
   
 | 
			
		||||
 | 
			
		||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
			
		||||
This  is  a  SWI-Prolog  implementation  of  the  corresponding  Quintus
 | 
			
		||||
library, based on the generalised arg/3 predicate of SWI-Prolog.
 | 
			
		||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
			
		||||
 | 
			
		||||
%%	contains_term(+Sub, +Term) is semidet.
 | 
			
		||||
%
 | 
			
		||||
%	Succeeds if Sub is contained in Term (=, deterministically)
 | 
			
		||||
 | 
			
		||||
contains_term(X, X) :- !.
 | 
			
		||||
contains_term(X, Term) :-
 | 
			
		||||
	compound(Term),
 | 
			
		||||
	genarg(_, Term, Arg),
 | 
			
		||||
	contains_term(X, Arg), !.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%%	contains_var(+Sub, +Term) is det.
 | 
			
		||||
%
 | 
			
		||||
%	Succeeds if Sub is contained in Term (==, deterministically)
 | 
			
		||||
 | 
			
		||||
contains_var(X0, X1) :-
 | 
			
		||||
	X0 == X1, !.
 | 
			
		||||
contains_var(X, Term) :-
 | 
			
		||||
	compound(Term),
 | 
			
		||||
	genarg(_, Term, Arg),
 | 
			
		||||
	contains_var(X, Arg), !.
 | 
			
		||||
 | 
			
		||||
%%	free_of_term(+Sub, +Term)
 | 
			
		||||
%
 | 
			
		||||
%	Succeeds of Sub does not unify to any subterm of Term
 | 
			
		||||
 | 
			
		||||
free_of_term(Sub, Term) :-
 | 
			
		||||
	\+ contains_term(Sub, Term).
 | 
			
		||||
 | 
			
		||||
%%	free_of_var(+Sub, +Term)
 | 
			
		||||
%
 | 
			
		||||
%	Succeeds of Sub is not equal (==) to any subterm of Term
 | 
			
		||||
 | 
			
		||||
free_of_var(Sub, Term) :-
 | 
			
		||||
	\+ contains_var(Sub, Term).
 | 
			
		||||
 | 
			
		||||
%%	occurrences_of_term(+SubTerm, +Term, ?Count)
 | 
			
		||||
%
 | 
			
		||||
%	Count the number of SubTerms in Term
 | 
			
		||||
 | 
			
		||||
occurrences_of_term(Sub, Term, Count) :-
 | 
			
		||||
	count(sub_term(Sub, Term), Count).
 | 
			
		||||
 | 
			
		||||
%%	occurrences_of_var(+SubTerm, +Term, ?Count)
 | 
			
		||||
%
 | 
			
		||||
%	Count the number of SubTerms in Term
 | 
			
		||||
 | 
			
		||||
occurrences_of_var(Sub, Term, Count) :-
 | 
			
		||||
	count(sub_var(Sub, Term), Count).
 | 
			
		||||
 | 
			
		||||
%%	sub_term(-Sub, +Term)
 | 
			
		||||
%
 | 
			
		||||
%	Generates (on backtracking) all subterms of Term.
 | 
			
		||||
 | 
			
		||||
sub_term(X, X).
 | 
			
		||||
sub_term(X, Term) :-
 | 
			
		||||
	compound(Term),
 | 
			
		||||
	genarg(_, Term, Arg),
 | 
			
		||||
	sub_term(X, Arg).
 | 
			
		||||
 | 
			
		||||
%%	sub_var(-Sub, +Term)
 | 
			
		||||
%
 | 
			
		||||
%	Generates (on backtracking) all subterms (==) of Term.
 | 
			
		||||
 | 
			
		||||
sub_var(X0, X1) :-
 | 
			
		||||
	X0 == X1.
 | 
			
		||||
sub_var(X, Term) :-
 | 
			
		||||
	compound(Term),
 | 
			
		||||
	genarg(_, Term, Arg),
 | 
			
		||||
	sub_var(X, Arg).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		 /*******************************
 | 
			
		||||
		 *		UTIL		*
 | 
			
		||||
		 *******************************/
 | 
			
		||||
 | 
			
		||||
%%	count(+Goal, -Count)
 | 
			
		||||
%
 | 
			
		||||
%	Count number of times Goal succeeds.
 | 
			
		||||
 | 
			
		||||
count(Goal, Count) :-
 | 
			
		||||
	State = count(0),
 | 
			
		||||
	(   Goal,
 | 
			
		||||
	    arg(1, State, N0),
 | 
			
		||||
	    N is N0 + 1,
 | 
			
		||||
	    nb_setarg(1, State, N),
 | 
			
		||||
	    fail
 | 
			
		||||
	;   arg(1, State, Count)
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										162
									
								
								library/pairs.pl
									
									
									
									
									
								
							
							
						
						
									
										162
									
								
								library/pairs.pl
									
									
									
									
									
								
							@@ -1,162 +0,0 @@
 | 
			
		||||
/*  $Id: pairs.pl,v 1.1 2008-02-12 17:03:52 vsc Exp $
 | 
			
		||||
 | 
			
		||||
    Part of SWI-Prolog
 | 
			
		||||
 | 
			
		||||
    Author:        Jan Wielemaker
 | 
			
		||||
    E-mail:        wielemak@science.uva.nl
 | 
			
		||||
    WWW:           http://www.swi-prolog.org
 | 
			
		||||
    Copyright (C): 1985-2006, University of Amsterdam
 | 
			
		||||
 | 
			
		||||
    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 General Public
 | 
			
		||||
    License along with this library; if not, write to the Free Software
 | 
			
		||||
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
:- module(pairs,
 | 
			
		||||
	  [ pairs_keys_values/3,
 | 
			
		||||
	    pairs_values/2,
 | 
			
		||||
	    pairs_keys/2,
 | 
			
		||||
	    group_pairs_by_key/2,
 | 
			
		||||
	    transpose_pairs/2,
 | 
			
		||||
	    map_list_to_pairs/3
 | 
			
		||||
	  ]).
 | 
			
		||||
 | 
			
		||||
/** <module> Operations on key-value lists
 | 
			
		||||
 | 
			
		||||
This module implements common operations on  Key-Value lists, also known
 | 
			
		||||
as  _Pairs_.  Pairs  have  great  practical  value,  especially  due  to
 | 
			
		||||
keysort/2 and the library assoc.pl.
 | 
			
		||||
 | 
			
		||||
This library is based  on  disussion   in  the  SWI-Prolog  mailinglist,
 | 
			
		||||
including specifications from Quintus and a  library proposal by Richard
 | 
			
		||||
O'Keefe.
 | 
			
		||||
 | 
			
		||||
@see	keysort/2, library(assoc)
 | 
			
		||||
@author Jan Wielemaker
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
%%	pairs_keys_values(?Pairs, ?Keys, ?Values) is det.
 | 
			
		||||
%
 | 
			
		||||
%	True if Keys holds the keys of Pairs and Values the values.
 | 
			
		||||
%	
 | 
			
		||||
%	Deterministic if any argument is instantiated to a finite list
 | 
			
		||||
%	and the others are either free or finite lists.
 | 
			
		||||
 | 
			
		||||
pairs_keys_values(Pairs, Keys, Values) :-
 | 
			
		||||
	(   nonvar(Pairs) ->
 | 
			
		||||
	    pairs_keys_values_(Pairs, Keys, Values)
 | 
			
		||||
	;   nonvar(Keys) ->
 | 
			
		||||
	    keys_values_pairs(Keys, Values, Pairs)
 | 
			
		||||
	;   values_keys_pairs(Values, Keys, Pairs)
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
pairs_keys_values_([], [], []).
 | 
			
		||||
pairs_keys_values_([K-V|Pairs], [K|Keys], [V|Values]) :-
 | 
			
		||||
	pairs_keys_values_(Pairs, Keys, Values).
 | 
			
		||||
 | 
			
		||||
keys_values_pairs([], [], []).
 | 
			
		||||
keys_values_pairs([K|Ks], [V|Vs], [K-V|Pairs]) :-
 | 
			
		||||
	keys_values_pairs(Ks, Vs, Pairs).
 | 
			
		||||
 | 
			
		||||
values_keys_pairs([], [], []).
 | 
			
		||||
values_keys_pairs([V|Vs], [K|Ks], [K-V|Pairs]) :-
 | 
			
		||||
	values_keys_pairs(Vs, Ks, Pairs).
 | 
			
		||||
 | 
			
		||||
%%	pairs_values(+Pairs, -Values) is det.
 | 
			
		||||
%
 | 
			
		||||
%	Remove the keys  from  a  list   of  Key-Value  pairs.  Same  as
 | 
			
		||||
%	pairs_keys_values(Pairs, _, Values)
 | 
			
		||||
 | 
			
		||||
pairs_values([], []).
 | 
			
		||||
pairs_values([_-V|T0], [V|T]) :-
 | 
			
		||||
	pairs_values(T0, T).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%%	pairs_keys(+Pairs, -Keys) is det.
 | 
			
		||||
%
 | 
			
		||||
%	Remove the values  from  a  list   of  Key-Value  pairs.  Same  as
 | 
			
		||||
%	pairs_keys_values(Pairs, Keys, _)
 | 
			
		||||
 | 
			
		||||
pairs_keys([], []).
 | 
			
		||||
pairs_keys([K-_|T0], [K|T]) :-
 | 
			
		||||
	pairs_keys(T0, T).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%%	group_pairs_by_key(+Pairs, -Joined:list(Key-Values)) is det.
 | 
			
		||||
%
 | 
			
		||||
%	Group values with the same key.  For example:
 | 
			
		||||
%	
 | 
			
		||||
%	==
 | 
			
		||||
%	?- group_pairs_by_key([a-2, a-1, b-4], X).
 | 
			
		||||
%	
 | 
			
		||||
%	X = [a-[2,1], b-[4]]
 | 
			
		||||
%	==
 | 
			
		||||
%	
 | 
			
		||||
%	@param	Pairs	Key-Value list, sorted to the standard order
 | 
			
		||||
%			of terms (as keysort/2 does)
 | 
			
		||||
%	@param  Joined	List of Key-Group, where Group is the
 | 
			
		||||
%			list of Values associated with Key. 
 | 
			
		||||
 | 
			
		||||
group_pairs_by_key([], []).
 | 
			
		||||
group_pairs_by_key([M-N|T0], [M-[N|TN]|T]) :-
 | 
			
		||||
	same_key(M, T0, TN, T1),
 | 
			
		||||
	group_pairs_by_key(T1, T).
 | 
			
		||||
 | 
			
		||||
same_key(M, [M-N|T0], [N|TN], T) :- !,
 | 
			
		||||
	same_key(M, T0, TN, T).
 | 
			
		||||
same_key(_, L, [], L).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%%	transpose_pairs(+Pairs, -Transposed) is det.
 | 
			
		||||
%
 | 
			
		||||
%	Swap Key-Value to Value-Key and sort the result on Value
 | 
			
		||||
%	(the new key) using keysort/2.
 | 
			
		||||
 | 
			
		||||
transpose_pairs(Pairs, Transposed) :-
 | 
			
		||||
	flip_pairs(Pairs, Flipped),
 | 
			
		||||
	keysort(Flipped, Transposed).
 | 
			
		||||
 | 
			
		||||
flip_pairs([], []).
 | 
			
		||||
flip_pairs([Key-Val|Pairs], [Val-Key|Flipped]) :-
 | 
			
		||||
	flip_pairs(Pairs, Flipped).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%%	map_list_to_pairs(:Function, +List, -Keyed)
 | 
			
		||||
%
 | 
			
		||||
%	Create a key-value list by mapping each element of List.
 | 
			
		||||
%	For example, if we have a list of lists we can create a
 | 
			
		||||
%	list of Length-List using
 | 
			
		||||
%	
 | 
			
		||||
%	==
 | 
			
		||||
%		map_list_to_pairs(length, ListOfLists, Pairs),
 | 
			
		||||
%	==
 | 
			
		||||
 | 
			
		||||
:- module_transparent
 | 
			
		||||
	map_list_to_pairs/3,
 | 
			
		||||
	map_list_to_pairs2/3.
 | 
			
		||||
 | 
			
		||||
map_list_to_pairs(Function, List, Pairs) :-
 | 
			
		||||
	map_list_to_pairs2(List, Function, Pairs).
 | 
			
		||||
 | 
			
		||||
map_list_to_pairs2([], _, []).
 | 
			
		||||
map_list_to_pairs2([H|T0], Pred, [K-H|T]) :-
 | 
			
		||||
	call(Pred, H, K),
 | 
			
		||||
	map_list_to_pairs2(T0, Pred, T).
 | 
			
		||||
 | 
			
		||||
@@ -1,32 +0,0 @@
 | 
			
		||||
#
 | 
			
		||||
# default base directory for YAP installation
 | 
			
		||||
#
 | 
			
		||||
ROOTDIR = @prefix@
 | 
			
		||||
#
 | 
			
		||||
# where the binary should be
 | 
			
		||||
#
 | 
			
		||||
BINDIR = $(ROOTDIR)/bin
 | 
			
		||||
#
 | 
			
		||||
# where YAP should look for binary libraries
 | 
			
		||||
#
 | 
			
		||||
LIBDIR=@libdir@/Yap
 | 
			
		||||
#
 | 
			
		||||
# where YAP should look for architecture-independent Prolog libraries
 | 
			
		||||
#
 | 
			
		||||
SHAREDIR=$(ROOTDIR)/share
 | 
			
		||||
#
 | 
			
		||||
#
 | 
			
		||||
# You shouldn't need to change what follows.
 | 
			
		||||
#
 | 
			
		||||
INSTALL=@INSTALL@
 | 
			
		||||
INSTALL_DATA=@INSTALL_DATA@
 | 
			
		||||
INSTALL_PROGRAM=@INSTALL_PROGRAM@
 | 
			
		||||
srcdir=@srcdir@
 | 
			
		||||
 | 
			
		||||
PROGRAMS= $(srcdir)/clp_events.pl
 | 
			
		||||
 | 
			
		||||
install: $(PROGRAMS)
 | 
			
		||||
	mkdir -p $(DESTDIR)$(SHAREDIR)/Yap
 | 
			
		||||
	mkdir -p $(DESTDIR)$(SHAREDIR)/Yap/clp
 | 
			
		||||
	for p in $(PROGRAMS); do $(INSTALL_DATA) $$p $(DESTDIR)$(SHAREDIR)/Yap/clp; done
 | 
			
		||||
 | 
			
		||||
@@ -1,89 +0,0 @@
 | 
			
		||||
/*  $Id: clp_events.pl,v 1.1 2005-10-28 17:53:27 vsc Exp $
 | 
			
		||||
 | 
			
		||||
    Part of SWI-Prolog
 | 
			
		||||
 | 
			
		||||
    Author:        Tom Schrijvers
 | 
			
		||||
    E-mail:        tom.schrijvers@cs.kuleuven.ac.be
 | 
			
		||||
    WWW:           http://www.swi-prolog.org
 | 
			
		||||
    Copyright (C): 2005, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | 
			
		||||
%
 | 
			
		||||
% Module for managing constraint solver events.
 | 
			
		||||
%
 | 
			
		||||
% Author: 	Tom Schrijvers
 | 
			
		||||
% E-mail: 	tom.schrijvers@cs.kuleuven.ac.be
 | 
			
		||||
% Copyright:	2005, K.U.Leuven
 | 
			
		||||
%
 | 
			
		||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | 
			
		||||
:-module(clp_events,
 | 
			
		||||
	[
 | 
			
		||||
		notify/2,
 | 
			
		||||
		subscribe/4,
 | 
			
		||||
		unsubscribe/2
 | 
			
		||||
	]).
 | 
			
		||||
 | 
			
		||||
notify(V,NMod) :-
 | 
			
		||||
	( get_attr(V,clp_events,List) ->
 | 
			
		||||
		notify_list(List,NMod)
 | 
			
		||||
	;
 | 
			
		||||
		true
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
subscribe(V,NMod,SMod,Goal) :-
 | 
			
		||||
	( get_attr(V,clp_events,List) ->
 | 
			
		||||
		put_attr(V,clp_events,[entry(NMod,SMod,Goal)|List])
 | 
			
		||||
	;
 | 
			
		||||
	        put_attr(V,clp_events,[entry(NMod,SMod,Goal)])
 | 
			
		||||
	).	
 | 
			
		||||
 | 
			
		||||
unsubscribe(V,SMod) :-
 | 
			
		||||
	( get_attr(V,clp_events,List) ->
 | 
			
		||||
		unsubscribe_list(List,SMod,NList),
 | 
			
		||||
		put_attr(V,clp_events,NList)
 | 
			
		||||
	;
 | 
			
		||||
		true
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
notify_list([],_).
 | 
			
		||||
notify_list([entry(Mod,_,Goal)|Rest],NMod) :-
 | 
			
		||||
	( Mod == NMod ->
 | 
			
		||||
		call(Goal)
 | 
			
		||||
	;
 | 
			
		||||
		true
 | 
			
		||||
	),
 | 
			
		||||
	notify_list(Rest,NMod).
 | 
			
		||||
	
 | 
			
		||||
unsubscribe_list([],_,_).
 | 
			
		||||
unsubscribe_list([Entry|Rest],SMod,List) :-
 | 
			
		||||
	Entry = entry(_,Mod,_),
 | 
			
		||||
	( Mod == SMod ->
 | 
			
		||||
		List = Rest
 | 
			
		||||
	;	
 | 
			
		||||
		List = [Entry|Tail],
 | 
			
		||||
		unsubscribe_list(Rest,SMod,Tail)
 | 
			
		||||
	).
 | 
			
		||||
 | 
			
		||||
attr_unify_hook(_,_).
 | 
			
		||||
@@ -34,7 +34,6 @@ PROGRAMS= \
 | 
			
		||||
	$(srcdir)/edit.pl \
 | 
			
		||||
	$(srcdir)/error.pl \
 | 
			
		||||
	$(srcdir)/main.pl \
 | 
			
		||||
	$(srcdir)/maplist.pl \
 | 
			
		||||
	$(srcdir)/menu.pl \
 | 
			
		||||
	$(srcdir)/nb_set.pl \
 | 
			
		||||
	$(srcdir)/occurs.yap \
 | 
			
		||||
 
 | 
			
		||||
@@ -1,103 +0,0 @@
 | 
			
		||||
/*  $Id: maplist.pl,v 1.2 2008-06-05 19:33:51 rzf Exp $
 | 
			
		||||
 | 
			
		||||
    Part of SWI-Prolog
 | 
			
		||||
 | 
			
		||||
    Author:        Jan Wielemaker
 | 
			
		||||
    E-mail:        jan@swi.psy.uva.nl
 | 
			
		||||
    WWW:           http://www.swi-prolog.org
 | 
			
		||||
    Copyright (C): 1985-2002, University of Amsterdam
 | 
			
		||||
 | 
			
		||||
    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
:- module(maplist,
 | 
			
		||||
	  [ maplist/2,			% :Goal, +List
 | 
			
		||||
	    maplist/3,			% :Goal, ?List1, ?List2
 | 
			
		||||
	    maplist/4,			% :Goal, ?List1, ?List2, ?List3
 | 
			
		||||
	    maplist/5,			% :Goal, ?List1, ?List2, ?List3, List4
 | 
			
		||||
	    forall/2			% :Goal, :Goal
 | 
			
		||||
	  ]).
 | 
			
		||||
 | 
			
		||||
:- module_transparent
 | 
			
		||||
	maplist/2, 
 | 
			
		||||
	maplist2/2, 
 | 
			
		||||
	maplist/3, 
 | 
			
		||||
	maplist2/3, 
 | 
			
		||||
	maplist/4, 
 | 
			
		||||
	maplist2/4, 
 | 
			
		||||
	maplist/5, 
 | 
			
		||||
	maplist2/5, 
 | 
			
		||||
	forall/2.
 | 
			
		||||
 | 
			
		||||
%	maplist(:Goal, +List)
 | 
			
		||||
%
 | 
			
		||||
%	True if Goal can succesfully be applied on all elements of List.
 | 
			
		||||
%	Arguments are reordered to gain performance as well as to make
 | 
			
		||||
%	the predicate deterministic under normal circumstances.
 | 
			
		||||
 | 
			
		||||
maplist(Goal, List) :-
 | 
			
		||||
	maplist2(List, Goal).
 | 
			
		||||
 | 
			
		||||
maplist2([], _).
 | 
			
		||||
maplist2([Elem|Tail], Goal) :-
 | 
			
		||||
	call(Goal, Elem), 
 | 
			
		||||
	maplist2(Tail, Goal).
 | 
			
		||||
 | 
			
		||||
%	maplist(:Goal, ?List1, ?List2)
 | 
			
		||||
%
 | 
			
		||||
%	True if Goal can succesfully be applied to all succesive pairs
 | 
			
		||||
%	of elements of List1 and List2.
 | 
			
		||||
 | 
			
		||||
maplist(Goal, List1, List2) :-
 | 
			
		||||
	maplist2(List1, List2, Goal).
 | 
			
		||||
 | 
			
		||||
maplist2([], [], _).
 | 
			
		||||
maplist2([Elem1|Tail1], [Elem2|Tail2], Goal) :-
 | 
			
		||||
	call(Goal, Elem1, Elem2), 
 | 
			
		||||
	maplist2(Tail1, Tail2, Goal).
 | 
			
		||||
 | 
			
		||||
%	maplist(:Goal, ?List1, ?List2, ?List3)
 | 
			
		||||
%
 | 
			
		||||
%	True if Goal can succesfully be applied to all succesive triples
 | 
			
		||||
%	of elements of List1..List3.
 | 
			
		||||
 | 
			
		||||
maplist(Goal, List1, List2, List3) :-
 | 
			
		||||
	maplist2(List1, List2, List3, Goal).
 | 
			
		||||
 | 
			
		||||
maplist2([], [], [], _).
 | 
			
		||||
maplist2([Elem1|Tail1], [Elem2|Tail2], [Elem3|Tail3], Goal) :-
 | 
			
		||||
	call(Goal, Elem1, Elem2, Elem3), 
 | 
			
		||||
	maplist2(Tail1, Tail2, Tail3, Goal).
 | 
			
		||||
 | 
			
		||||
%	maplist(:Goal, ?List1, ?List2, ?List3, List4)
 | 
			
		||||
%
 | 
			
		||||
%	True if Goal  can  succesfully  be   applied  to  all  succesive
 | 
			
		||||
%	quadruples of elements of List1..List4
 | 
			
		||||
 | 
			
		||||
maplist(Goal, List1, List2, List3, List4) :-
 | 
			
		||||
	maplist2(List1, List2, List3, List4, Goal).
 | 
			
		||||
 | 
			
		||||
maplist2([], [], [], [], _).
 | 
			
		||||
maplist2([Elem1|Tail1], [Elem2|Tail2], [Elem3|Tail3], [Elem4|Tail4], Goal) :-
 | 
			
		||||
	call(Goal, Elem1, Elem2, Elem3, Elem4), 
 | 
			
		||||
	maplist2(Tail1, Tail2, Tail3, Tail4, Goal).
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user