ciao-lang / ciao

Ciao is a modern Prolog implementation that builds up from a logic-based simple kernel designed to be portable, extensible, and modular.
https://ciao-lang.org
GNU Lesser General Public License v3.0
268 stars 20 forks source link

Feature request library(aggregate) from SICStus Prolog #59

Open Jean-Luc-Picard-2021 opened 2 years ago

Jean-Luc-Picard-2021 commented 2 years ago

I did a search in this repository about aggregate_all/3. But I didn't find it. Is this correct that Ciao Prolog has no library(aggregate) from SICStus Prolog?

An Aggregation Operator for Data-Base-Style Queries https://sicstus.sics.se/sicstus/docs/4.6.0/html/sicstus/lib_002daggregate.html

I am somehow used to it since it also found its way into SWI-Prolog. Would it be possible to support the same in Ciao Prolog as well? Its not urgent, just a feature request.

Here is an example test case:

?- aggregate_all(count, (between(1,1000,N), N mod 13 =:= 0), C).
C = 76.

?- aggregate_all(sum(N), (between(1,1000,N), N mod 13 =:= 0), C).
C = 38038.
Jean-Luc-Picard-2021 commented 2 years ago

With Novacore and Liblets its not needed anymore.

jfmc commented 2 years ago

Adding those predicates would still be an enhancement for Ciao. I reopen it.

Jean-Luc-Picard-2021 commented 1 year ago

Is there a ciao version where this is already available? Some library aggregate.? I now did for example this:

:- use_module(library(numlists)).

aggregate_all(sum(X), G, S) :-
   findall(X, G, L),
   sum_list(L, S).

But it doesn't work, when I call it with this here:

?- use_module(library(between)).
?- use_module(library(random)).
?- ['aggregate.p'].

?- E is (1<<100), M is (1<<101), K is (1<<20),
between(1,10,_), aggregate_all(sum(X),
(between(1,K,_), random(0,M,X)), S),
N is msb(abs(S-E*K))-20, write(N), nl, fail; true.
{ERROR: user:random/3 - existence error: procedure:user:random/3 does not exist}

Whats missing, a meta predicate declaration before aggregate_all?

mherme commented 1 year ago

Random number generation is in library(random): http://ciao-lang.org/ciao/build/doc/ciao.html/random.html

Calling random(0,M,X) should give you what you need. You can also of course skip defining aggregate_all, just put in the query findall(X, (between(1,K,_), random(0,M,X)), L), sum_list(L,S), ....

mherme commented 1 year ago

(I edited the previous comment)

Jean-Luc-Picard-2021 commented 1 year ago

random/3 was not part of my comment or ticket here, the code I posted already calls random(0,M,_), no editing done. This was on SWI-Prolog discourse. There I observed that your

random/3 generates in the interval [L,H] whereas SWI-Prolog generates in the interval [L,H). Translated to SWI-Prolog you need to call random(0,M+1,_). I didn't open any ticket or made

any comment about random/3 on Ciao Prolog GitHub issues. Should there be a discussion about random/3? I don't know, what are your plans? I don't know? Is there a road map? I don't

know. Does anybody care Ciao and SWI-Prolog compatibility? I don't know? Recenfly SWI-Prolog deprecated random/3 and introduced random_between/3 with a different protocoll.

Maybe this can point the way forward?

Jean-Luc-Picard-2021 commented 1 year ago

just put in the query findall(X, (between(1,K,_), random(0,M,X)), L), sum_list(L,S), ....

Interestingly that was just what I defined:

aggregate_all(sum(X), G, S) :-
   findall(X, G, L),
   sum_list(L, S).

But why does it throw a random/3 existence error. Should I place a meta_predicate directive before aggregate_all/3? I imported random/3 already into user:

?- use_module(library(random)).

but the error messsage says:

{ERROR: user:random/3 - existence error: procedure:user:random/3 does not exist}

Will try with a meta predicate directive soon.

mherme commented 1 year ago

Humm, it works for me:

?- use_module(library(random)), use_module(library(numlists)). 

yes
?- random(0,5,X).

X = 1 ? 

Is this what you are doing?

Jean-Luc-Picard-2021 commented 1 year ago

Here is a screenshot of what I already copy pasted into the ticket here:

image

The scrambling of the input, the 3 blanks ' ' is an artefact of your Ciao Prolog readline routine somehow, when pasting a multi-line query. So the screenshot doesn't look that pretty. What I pasted into the ticket here

looks more pretty. It has also removed Note:, yes, yes, yes, aborted.

mherme commented 1 year ago

Ah, I understand now: make aggregate a module (just put :- module(_,_). at the beginning) and include the meta-predicate declaration: :- meta_predicate( aggregate_all(_,goal,_))..

Jean-Luc-Picard-2021 commented 1 year ago

Now I could run it. The error in Ciao Prolog is much larger than in SWI-Prolog, i.e. the distance to the expected value. Was using this query, taking into account the different random/3 protocoll, and

the missing aggregate_all/3 and msb/1 evaluable function:

$ ciaosh
Ciao 1.22.0 (2022-09-28 21:20:35 +0200) [LINUXx86_64]
?- use_module(library(between)).

?- ['aggregate.p'].

?- E is (1<<100), M is (1<<101), K is (1<<20),
between(1,10,_), aggregate_all(sum(X),
(between(1,K,_), random(0,M,X)), S),
H is abs(S-E*K), msb(H,J), N is J-20, write(N), nl, fail; true.
100.0
100.0
100.0
100.0
100.0
100.0
100.0
100.0
100.0
100.0

And this helper code (file aggregate.p):

:- use_module(library(numlists)).
:- use_module(library(random)).

aggregate_all(sum(X), G, S) :-
   findall(X, G, L),
   sum_list(L, S).

msb(X, Y) :- Y is log(X)/log(2).
Jean-Luc-Picard-2021 commented 1 year ago

Also a little strange that it is exactly 100.0 in all runs? Have to dig deeper whats going on.