Состав списка 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.
Надеюсь, что это поможет кому-то еще в будущем.