DLV list composition

2019-09-03 16:50发布

问题:

I was wondering if there is a way in DLV for creating a list with the elements of all predicates that are true in a rule. For example, if I have the following predicates

foo(a, b).
foo(a, c).
foo(a, e).
foo(b, c).

The result I am looking for should be new predicates where the first element is the first parameter of foo and the second parameter should contain a list with all the elements associated to the first parameter. Empirically:

bar(a, [b,c,e]).
bar(b, [c]).

I know there is a way of getting these results (plus many more) with the following code:

bar(A, [X]) :-  foo(A, X).
bar(A,  P ) :-  bar(A, P0),
                foo(A, X), 
                not #member(X, P0),
                #insLast(P0, X, P).

But I would like to know if there is a way of preventing the generation of all possible lists of size from 1 to N (being N the number of elements of the final list). I would like to do it for two reasons: (1) reduce computational cost (2) prevent discarding all unnecessary predicates.

If the computational cost was not a problem, which may be the case, I was thinking of the following changes in order to keep only the predicates with the largest lists:

tmp_bar(A, [X], 1) :-   foo(A, X).
tmp_bar(A,  P,  L) :-   tmp_bar(A, P0, L0),
                        foo(A, X), 
                        not #member(X, P0),
                        #insLast(P0, X, P),
                        L = L0 + 1.
bar(A, P)      :- tmp_bar(A, P, L), 
                  max_list(A, L).
max_list(A, L) :- foo(A, _), 
                  #max{X: tmp_bar(A, P, X)} = L.

However, this starts to get complicated and is showing all of the lists of maximum size and not only one of them. How do I get rid of all but one? I tried generating bar(A,P) only in case their is no other bar(A, _) but I get "rule is not safe". Also tried counting the number of occurrences and similar problems appear...

Most importantly, is it possible to get the results I expect all at once without that many tricks?

Any help is appreciated,

Thanks!

回答1:

Apparently I found a solution to the problem by adding elements in a particular order. What I do is to add the element at the end of the list only if its smaller than the last element of the current list. I was dealing with names rather than numbers so I though this wasn't possible).

Here is the code:

tmp_bar(A, [X], 1) :-   foo(A, X).
tmp_bar(A,  P,  L)  :-  tmp_bar(A, P0, L0),
                        foo(A, X), 
                        #last(P0, Y),
                        Y < X,
                        #insLast(P0, X, P),
                        L = L0 + 1.

bar(A, P) :- tmp_bar(A, P, L), 
             max_list(A, L).

max_list(A, L) :- foo(A, _), 
                 #max{X: tmp_bar(A, P, X)} = L.

Hope it helps someone else in the future.