优化Prolog程序(删除重复项,重复重新计算)

优化Prolog程序(删除重复项,重复重新计算),prolog,datalog,answer-set-programming,Prolog,Datalog,Answer Set Programming,我对序言非常缺乏经验。我有一个包含元素和关系的数据集,它在图中具有循环性(相当多)。有一些规则可以计算路径的摘要关系。其中之一是:一个人走这条路,然后走最薄弱的关系,那就是两端之间的关系 与 元素E1,E2,E3和 关系R1/R1c,R2,R3(强度从低到高)和 结构E1-R3-E2,E1-R1-E2,E2-R2-E3,E3-R1-E2 我可以举一个简单的例子: % weaker table isWeaker( r1, r2). isWeaker( r2, r3). weaker( X, Y)

我对序言非常缺乏经验。我有一个包含元素和关系的数据集,它在图中具有循环性(相当多)。有一些规则可以计算路径的摘要关系。其中之一是:一个人走这条路,然后走最薄弱的关系,那就是两端之间的关系

与 元素
E1
E2
E3

关系
R1/R1c
R2
R3
(强度从低到高)和
结构
E1-R3-E2
E1-R1-E2
E2-R2-E3
E3-R1-E2

我可以举一个简单的例子:

% weaker table
isWeaker( r1, r2).
isWeaker( r2, r3).
weaker( X, Y) :- isWeaker( X, Y).
weaker( X, Y) :-
    isWeaker( X, Z),
    weaker( Z, Y).
% 'weakest' is <= not <
weakest( X, X, Y) :- =(X,Y).
weakest( X, X, Y) :- weaker( X, Y).

% All direct relations
isADirectRelation( e1, r1, e2).
isADirectRelation( e1, r3, e2).
isADirectRelation( e2, r2, e3).
isADirectRelation( e3, r1, e2).
isADirectRelation( e1, r3, e4).
isADirectRelation( e4, r2, e3).
isADirectRelation( e1, r1, e4).
isADirectRelation( e3, r1, e4).

% derived relations calculations

% Structural Chains
isADerivedRelation( Source, Relation, Target, Visited) :-
    \+ member( [Source,Relation,Target], Visited),
    weakest( Relation, RelationOne, RelationTwo),
    isARelation( Source, RelationOne, Intermediate, [[Source,Relation,Target]|Visited]),
    isARelation( Intermediate, RelationTwo, Target, [[Source,Relation,Target]|Visited]).

% major workhorse with anti-circularity
isARelation( Source, Relation, Target, Visited) :-
    (isADirectRelation( Source, Relation, Target);
     isADerivedRelation( Source, Relation, Target, Visited)).
失踪的是

e4,r1,e4
e2,r2,e2

在Prolog中解决这个问题有可能吗?从形式上来说,是的,当然,但也有一个体面的表现?

关于这个问题有很多话要说,所以这将是一个冗长、漫无边际、最终令人不满意的答案。因此,我不妨从一个恼怒的话题开始:请不要对谓词使用
camelCaseIdentifiers
,我们通常使用
下划线分隔词。我不知道为什么这会让我在Prolog中特别烦恼,但我怀疑部分原因是大写字母在语法上很重要

继续,您的
最弱/3
谓词被破坏:

?- weakest(Weakest, r2, r1).
false.
我认为你在问题的第一个版本中有这个权利,但是你删除了最弱/3的第三个子句,因为你认为这会导致多余的答案。不用说,没有正确性,“效率”是无用的。(此外,我们通常将“output”参数放在最后,而不是第一位。)

得到多余答案的部分原因是在
isaderiedvedrelation/4
中使用了两个(间接)递归调用
isarrelation/4
。您所计算的是类似于“直接”关系联合的传递闭包。在Prolog中表达传递闭包的常用方法如下:

transitive_closure(A, B) :-
    base_relation(A, B).
transitive_closure(A, C) :-
    base_relation(A, B),
    transitive_closure(B, C).
也就是说,我们首先“采取基本步骤”,然后递归。如果我们的基关系有对
a-b
b-c
c-d
,那么这将找到解决方案
a-d
,就像基对
a-b
和派生传递对
b-d
的组合一样。相反,如果我们像你一样构造第二个子句,通过两次递归调用
transitive_closure/2
,我们将得到解决方案
a-d
两次:一次如上所述,但也一次,因为我们将导出transitive对
a-c
,并将其与
c-d
组合,得到
a-d

您可以通过将在
isaderiedvedrelation/4
中的第一个
isARelation/4
调用更改为对
isADirectRelation/3
的调用来解决此问题

另一个问题是,您使用的
已访问
错误:在您证明此解决方案存在之前,您正在将该对
源目标
标记为已访问!您可能应该将
源中间层
标记为已访问

即使如此,如果图中的一对元素之间存在多条不同的路径,您仍然会得到这些元素的冗余解决方案。Prolog的逻辑就是这样工作的:Prolog会为您的查询找到单独的答案,但不允许您直接谈论这些答案之间的关系。如果我们想强迫它只列举一次,我们必须留下纯逻辑

一些Prolog系统提供了一种称为“tabling”的功能,它本质上缓存了“tabled”谓词的所有解决方案,并避免了重复计算。这应该避免重复回答,甚至可以简化您的定义:如果您的闭包关系是表格化的,您就不再需要跟踪
已访问的
列表,因为表格化将避免循环重新计算。我不能给你测试过的代码,因为我没有关于tabling的序言。即使没有您的系统提供的表格,也有使用Prolog不纯数据库自己“记忆”解决方案的理论可能性。如果没有多余的解决方案,很难做到完全正确

作为不纯序言的替代,您的问题似乎更适合或。这些编程模型使用类似于Prolog的语法,但其集合语义似乎正是您想要的:一个命题要么是解决方案,要么不是解决方案,没有冗余解决方案的概念。整个解决方案集是一次性计算的。循环消除也是自动的,因此您不需要(事实上,由于受限制的输入语言,无法使用)访问的
列表。如果我是你,我会尝试在数据日志中这样做

作为Prolog的进一步扩展,可能会有一个基于约束处理规则(Constraint Handling Rules,CHR)的spiffy解决方案。但实际上,请尝试使用数据日志


最后,我不明白你为什么认为
e2,r2,e2
是一个缺失的解决方案。我看到的从
e2
e2
的唯一路径是通过
e3
然后通过
r1
关系返回到
e2
,这是最弱的关系,因此解决方案应该是
e2,r1,e2
,多亏了潜伏者的评论和伊莎贝尔的回答,我最终得到的结果是:

% weaker table
isWeaker( r1, r2).
isWeaker( r2, r3).
weaker( X, Y) :- isWeaker( X, Y).
weaker( X, Y) :-
    isWeaker( X, Z),
    weaker( Z, Y).
% 'weakest' is <= not <
weakest( X, X, Y) :- =(X,Y).
weakest( X, X, Y) :- weaker( X, Y).

% All direct relations
isADirectRelation( e1, r1, e2).
isADirectRelation( e1, r3, e2).
isADirectRelation( e2, r2, e3).
isADirectRelation( e3, r1, e2).
isADirectRelation( e1, r3, e4).
isADirectRelation( e4, r2, e3).
isADirectRelation( e1, r1, e4).
isADirectRelation( e3, r1, e4).

% derived relations calculations

isARelation( Source, Relation, Target, _) :-
    isADirectRelation( Source, Relation, Target).

% Structural Chains
isARelation( Source, Relation, Target, Visited) :-
    \+ member( [Source,Relation,Target], Visited),
    weakest( Relation, RelationOne, RelationTwo),
    isADirectRelation( Source, RelationOne, Intermediate),
    isARelation( Intermediate, RelationTwo, Target, [[Source,RelationOne,Intermediate]|Visited]).
isARelation( Source, Relation, Target, Visited) :-
    \+ member( [Source,Relation,Target], Visited),
    weakest( Relation, RelationOne, RelationTwo),
    isADirectRelation( Source, RelationTwo, Intermediate),
    isARelation( Intermediate, RelationOne, Target, [[Source,RelationTwo,Intermediate]|Visited]).

write_relation( Result) :-
    write( Result), nl.

writeAllRelations :-
   setof( (Relation, Source, Target), Relation^isARelation( Source, Relation, Target, []), ListOfAllRelations),
% maplist( write_relation, ListOfAllRelations). % For SWIProlog
write( ListOfAllRelations). % for JIProlog

然而,在现实世界中,有60个左右的实体和800个左右的直接关系,我还没有找到一个Prolog可以处理它。我将查看数据日志。

您确定Prolog是要使用的语言\工具吗?一个小观察:
\+成员([Source,Relation,Target],visted)
isaderievedRelation/4
开头的调用与
isarrelation/4
中的调用是多余的,假设
isaderiedRelationship/4
也仅从已经检查过它的地方调用。我也很好奇你为什么写,
=(X,Y)
而不是
X=Y
,或者更简单地说,
最弱的(X,X,X)。
而不是
最弱的(最弱的,X,Y):-=(Wea
% weaker table
isWeaker( r1, r2).
isWeaker( r2, r3).
weaker( X, Y) :- isWeaker( X, Y).
weaker( X, Y) :-
    isWeaker( X, Z),
    weaker( Z, Y).
% 'weakest' is <= not <
weakest( X, X, Y) :- =(X,Y).
weakest( X, X, Y) :- weaker( X, Y).

% All direct relations
isADirectRelation( e1, r1, e2).
isADirectRelation( e1, r3, e2).
isADirectRelation( e2, r2, e3).
isADirectRelation( e3, r1, e2).
isADirectRelation( e1, r3, e4).
isADirectRelation( e4, r2, e3).
isADirectRelation( e1, r1, e4).
isADirectRelation( e3, r1, e4).

% derived relations calculations

isARelation( Source, Relation, Target, _) :-
    isADirectRelation( Source, Relation, Target).

% Structural Chains
isARelation( Source, Relation, Target, Visited) :-
    \+ member( [Source,Relation,Target], Visited),
    weakest( Relation, RelationOne, RelationTwo),
    isADirectRelation( Source, RelationOne, Intermediate),
    isARelation( Intermediate, RelationTwo, Target, [[Source,RelationOne,Intermediate]|Visited]).
isARelation( Source, Relation, Target, Visited) :-
    \+ member( [Source,Relation,Target], Visited),
    weakest( Relation, RelationOne, RelationTwo),
    isADirectRelation( Source, RelationTwo, Intermediate),
    isARelation( Intermediate, RelationOne, Target, [[Source,RelationTwo,Intermediate]|Visited]).

write_relation( Result) :-
    write( Result), nl.

writeAllRelations :-
   setof( (Relation, Source, Target), Relation^isARelation( Source, Relation, Target, []), ListOfAllRelations),
% maplist( write_relation, ListOfAllRelations). % For SWIProlog
write( ListOfAllRelations). % for JIProlog
r1,e1,e2
r1,e1,e3
r1,e1,e4
r1,e2,e2
r1,e2,e3
r1,e2,e4
r1,e3,e2
r1,e3,e3
r1,e3,e4
r1,e4,e2
r1,e4,e3
r1,e4,e4
r2,e1,e3
r2,e2,e3
r2,e4,e3
r3,e1,e2
r3,e1,e4