Хорошо, то, что вы описываете, безусловно, может быть достигнуто с помощью стандартного журнала данных без введения циклических отрицательных зависимостей. Вам нужны две вещи
forall p = ! exists ! p
, которые, кажется, вы уже поняли - разделение базового свойства и производного свойства
Вот очень общий c пример, который вы можете легко адаптировать.
Вот простой график: узлы с +
обладают свойством basi c (базовый случай). Те, у которых отмечены * - это те, для которых все преемники удовлетворяют этому свойству.
1 -- 2 -- 3 * --- 5 + *
|\ \----- 6 + *
| \-- 4 * -- 8 + *
\---- 7
Сначала закодируйте граф.
transition(1,2).
transition(2,3).
transition(2,4).
transition(3,5).
transition(3,6).
transition(2,7).
transition(4,8).
Вспомогательный для перечисления всех узлов.
node(Node) :- transition(Node, _).
node(Node) :- transition(_, Node).
Отметьте базовый вариант (+
узлов).
property(5).
property(6).
property(8).
Найдите узлы, которые не имеют свойства.
notProperty(Node) :- node(Node), ! property(Node).
Теперь мы выясняем *
узлов . Либо мы знаем это банально через property(Node)
. Или что мы можем перейти к узлу, где это свойство не выполняется.
propertyDerived(Node) :- property(Node).
propertyDerived(Node) :- transition(Node,Next), ! notProperty(Next).
Программа может избежать циклического отрицания, потому что я отделил propertyDerived
от property
, что в вашем примере сбит с толку.
Теперь, если вы запросите, вы получите то, что ожидаете!
?- propertyDerived(Node).
3
4
5
6
8