Состав списка DLV

Мне было интересно, есть ли способ в DLV для создания списка с элементами всех предикатов, которые являются истинными в правиле. Например, если у меня есть следующие предикаты

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

Результат, который я ищу, должен быть новыми предикатами, где первый элемент является первым параметром foo и второй параметр должен содержать список со всеми элементами, связанными с первым параметром. Эмпирически:

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

Я знаю, что есть способ получить эти результаты (и многие другие) с помощью следующего кода:

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

Но я хотел бы знать, есть ли способ предотвратить генерацию всех возможных списков размером от 1 до N (если N число элементов в окончательном списке). Я хотел бы сделать это по двум причинам: (1) уменьшить вычислительные затраты (2) предотвратить отбрасывание всех ненужных предикатов.

Если вычислительные затраты не были проблемой, что может иметь место, я думал о следующих изменениях, чтобы сохранить только предикаты с самыми большими списками:

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.

Однако, это начинает усложняться и показывает все списки максимального размера, а не только один из них. Как мне избавиться от всего, кроме одного? Я попытался сгенерировать bar(A,P) только в том случае, если их нет (A, _), но я получаю "правило не безопасно". Также пробовал подсчитывать количество вхождений и появляются похожие проблемы...

Самое главное, возможно ли получить ожидаемые результаты одновременно без такого количества уловок?

Любая помощь приветствуется,

Спасибо!

1 ответ

Видимо, я нашел решение проблемы, добавив элементы в определенном порядке. Что я делаю, так это добавляю элемент в конец списка, только если он меньше, чем последний элемент текущего списка. Я имел дело с именами, а не числами, поэтому я думал, что это было невозможно).

Вот код:

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.

Надеюсь, что это поможет кому-то еще в будущем.

Другие вопросы по тегам