Library(aggregate): Weird stuff!

I have been exercising library(aggregate) a bit, here are

However, I have immediately hit a snag. avg gives me a false.

?- aggregate(avg(M),C^car_cyl_mpg(C,M),R).
false.

The helper predicate car_cyl_mpg(C,M) generates cylinder/miles-per-gallon tuples:

bagof([C,M],car_cyl_mpg(C,M),L).
L = [[6, 21.0], [6, 21.0], [4, 22.8], [6, 21.4], [8, 18.7], [6, 18.1], [8, 14.3], [4|...], [...|...]|...].

and it works for max for example:

?- aggregate(max(M),C^car_cyl_mpg(C,M),R),unpump(R).  % Same
Result: the value 33.9
R = 33.9.

Does anybody have a hint what’s going on?

I used sum+count to compute average (avg doesn’t seem to be defined in template…).
For instance

?- L=[1,2,3,4],aggregate(t(sum(X),count),member(X,L),t(Sum,Count)),Ave is Sum/Count.
L = [1, 2, 3, 4],
Sum = 10,
Count = 4,
Ave = 2.5.
1 Like

Yeah, there is a small inconsistency in the validation of the
aggregate functions in SWI-Prolog. An unknown aggregate function
is return as is. For example avg/1 is unknown, and hence we get:

?- aggregate_all(avg(sum(X)), member(X,[1,2,3]), R).
R = avg(6).

?- aggregate(avg(sum(X)), member(X,[1,2,3]), R).
R = avg(6).

This handling of unknown aggregate functions is useful since for
example t/2 is also unknown, and we can apply two aggregates as
in CapelliC aggregate/3 call. Although I prefer using (’,’)/2 sometimes.

Now things get tricky, when we forget about at least
one aggregate function at all. I guess there should be
an instantiation error, but instead aggregate_all/3 assumes

a sum/1 aggregate function and aggregate/3 fails:

?- aggregate_all(foo(X), member(X,[1,2,3]), R).
X = sum(_10138),
R = foo(0).

?- aggregate(foo(X), member(X,[1,2,3]), R).
false.

I guess this could be fixed. At least order_by has a better error handling,
it indeed gives an instantiation error if the order function is missing:

?- order_by([desc(X)], member(X,[1,2,3])).
X = 3 ;
X = 2 ;
X = 1.

?- order_by([X], member(X,[1,2,3])).
ERROR: Arguments are not sufficiently instantiated
1 Like

It follows (AFAIK) the rules of the SICStus module with the same name: the template can be any term, of which some sub-terms are recognised. So you can do multiple aggregations at the same time and define the result structure. This allows for e.g.

?- aggregate_all(sum(X)/count, between(1, 1 000 000, X), Expr), Avg is Expr.
Expr = 500000500000/1000000,
Avg = 1000001/2.

Possibly someone with SICStus can verify that is (still) the case. I’m happy to make this a little tighter, but keeping this library in sync with SICStus has value too.

1 Like