:- module(aggregate, [ aggregate_all/3, aggregate/3 ]). :- meta_predicate aggregate_all(?,0,-), aggregate(?,^,-). /** * aggregate_all(A, G, S): * The predicate aggregates A for the solutions of G and unifies the * result with S. Works like findall/3, without witness grouping. See * documentation for the supported aggregates functions. */ % aggregate_all(+Aggregate, +Goal, -Term) aggregate_all(A, G, S) :- sys_aggr_init(A, T, I), findall(T, G, L), sys_aggr_compute(L, A, I, S). /** * aggregate(A, G, S): * The predicate aggregates A for the solutions of G and unifies the * result with S. Works like bagof/3, with witness grouping. See * documentation for the supported aggregates functions. */ % aggregate(+Aggregate, +Goal, -Term) aggregate(A, G, S) :- sys_aggr_init(A, T, I), bagof(T, G, L), sys_aggr_compute(L, A, I, S). % sys_aggr_compute(+List, +Aggregate, +Term, -Term) sys_aggr_compute([], A, I, S) :- sys_aggr_fini(A, I, S). sys_aggr_compute([T|L], A, I, S) :- sys_aggr_next(A, I, T, J), sys_aggr_compute(L, A, J, S). % sys_aggr_init(+Aggregate, -Term, -Term) sys_aggr_init(A, _, _) :- var(A), throw(error(instantiation_error,_)). sys_aggr_init(count, '', 0) :- !. sys_aggr_init(sum(X), X, 0) :- !. sys_aggr_init(mul(X), X, 1) :- !. sys_aggr_init(min(X), X, sup) :- !. sys_aggr_init(max(X), X, inf) :- !. sys_aggr_init(bag(X), X, []) :- !. sys_aggr_init(set(X), X, []) :- !. sys_aggr_init((F,G), (X,Y), (C,D)) :- !, sys_aggr_init(F, X, C), sys_aggr_init(G, Y, D). sys_aggr_init(A, _, _) :- throw(error(type_error(aggregate,A),_)). % sys_aggr_next(+Aggregate, +Term, +Term, -Term) sys_aggr_next(count, A, '', C) :- C is A+1. sys_aggr_next(sum(_), A, B, C) :- C is A+B. sys_aggr_next(mul(_), A, B, C) :- C is A*B. sys_aggr_next(min(_), A, B, C) :- sys_min(A, B, C). sys_aggr_next(max(_), A, B, C) :- sys_max(A, B, C). sys_aggr_next(bag(_), A, B, [B|A]). sys_aggr_next(set(_), A, B, [B|A]). sys_aggr_next((F,G), (A,B), (X,Y), (C,D)) :- sys_aggr_next(F, A, X, C), sys_aggr_next(G, B, Y, D). % sys_aggr_fini(+Aggregate, +Term, -Term) sys_aggr_fini(count, A, A). sys_aggr_fini(sum(_), A, A). sys_aggr_fini(mul(_), A, A). sys_aggr_fini(min(_), A, A). sys_aggr_fini(max(_), A, A). sys_aggr_fini(bag(_), A, B) :- reverse(A, B). sys_aggr_fini(set(_), A, B) :- reverse(A, H), sort(H, B). sys_aggr_fini((F,G), (X,Y), (C,D)) :- sys_aggr_fini(F, X, C), sys_aggr_fini(G, Y, D). % sys_min(+ExtNumber, +ExtNumber, -ExtNumber) sys_min(sup, X, R) :- !, R = X. sys_min(X, sup, R) :- !, R = X. sys_min(inf, _, R) :- !, R = inf. sys_min(_, inf, R) :- !, R = inf. sys_min(X, Y, R) :- R is min(X, Y). % sys_max(+ExtNumber, +ExtNumber, -ExtNumber) sys_max(inf, X, R) :- !, R = X. sys_max(X, inf, R) :- !, R = X. sys_max(sup, _, R) :- !, R = sup. sys_max(_, sup, R) :- !, R = sup. sys_max(X, Y, R) :- R is max(X, Y).