Prolog 组合纯谓词

Prolog 组合纯谓词,prolog,logical-purity,Prolog,Logical Purity,我试图结合前面堆栈溢出问题中的一些纯谓词来生成我自己的谓词 我想给出一个c的列表(与它们相关联的事实-‘at’)和一个‘feature’术语,它有一个运算符和一个‘at’的阈值。我想对c的列表进行分区,如果c没有“feature”中相应的“at”,它将进入假分区,否则操作员将测试该“c”的“at”,并适当地拆分c 例如: ?-cpgpartition_ts_fs_feature([c1,c2,c3],Ts,Fs,feature(at2,_,>=,10)). 应导致: Ts = [c3],

我试图结合前面堆栈溢出问题中的一些纯谓词来生成我自己的谓词

我想给出一个c的列表(与它们相关联的事实-‘at’)和一个‘feature’术语,它有一个运算符和一个‘at’的阈值。我想对c的列表进行分区,如果c没有“feature”中相应的“at”,它将进入假分区,否则操作员将测试该“c”的“at”,并适当地拆分c

例如:

?-cpgpartition_ts_fs_feature([c1,c2,c3],Ts,Fs,feature(at2,_,>=,10)).
应导致:

Ts = [c3], %c3 has an at2 >= 10
Fs = [c1,c2]. %c1 has at2 <10 and c2 does not have an at2
有趣的是,如果clist的顺序不同,结果也会改变

?- cpgpartition_ts_fs_feature([c3,c1,c2],Ts,Fs,feature(at2,_,>=,10)).
Ts = [c3|_12950],
Fs = [c1, c2] ;
Ts = [c3|_12950],
Fs = [c1, c2] ;
Fs = [c3, c1, c2] ;
Fs = [c3, c1, c2].
我认为这是因为下面的查询返回的结果带有
dif/2
约束,这些约束似乎不适合我正在尝试做的事情,我只想要具体的解决方案

    ?- cpg_ats_i(C,Ats),   if_(memberd_t(attribute(at2,AtValue),Ats),Q=true,Q=false).
C = c1,
Ats = [attribute(at1, 50), attribute(at2, 3)],
AtValue = 3,
Q = true ;
C = c1,
Ats = [attribute(at1, 50), attribute(at2, 3)],
Q = false,
dif(AtValue, 3) ;
C = c2,
Ats = [attribute(at1, 2)],
Q = false ;
C = c3,
Ats = [attribute(at2, 10), attribute(at3, 4), attribute(at4, 8)],
AtValue = 10,
Q = true ;
C = c3,
Ats = [attribute(at2, 10), attribute(at3, 4), attribute(at4, 8)],
Q = false,
dif(AtValue, 10).

另外,这段代码的目的是在一大组数据上运行,c的列表长度将达到数十万,每个c可能有50k的ats,我如何计算内存需求?使用不纯谓词的另一种方法可能占用更少的内存吗

正如您所提到的,问题在于以下定义中的dif(X,Y)行:

=(X, Y, T) :-
   (  X == Y -> T = true
   ;  X \= Y -> T = false
   ;  T = true, X = Y
   ;  T = false,
      dif(X, Y)                             % ISO extension
      % throw(error(instantiation_error,_)) % ISO strict
   ).
这是因为如果你尝试:

memberd_t(attribute(at2,X),[attribute(at1,0.5),attribute(at2,0.03)],T).
X = 0.03,
T = true ;
T = false,
dif(X, 0.03).
这里给出解决方案的选择点:
T=false,dif(X,0.03)。
将导致执行以下部分的
Fs=[X | Fs0]

if_(memberd_t(attribute(At,AtValue3),AtList),
       (
       if_(call(Test), (Ts=[X|Ts0],Fs=Fs0),
       (   Ts =Ts0,Fs=[X|Fs0]))
       )
       ,Fs=[X|Fs0]),
此外,这也是不正确的响应,因为如果在
Atlist
中有属性(at2,0.03),您希望
memberd\u t
返回
X=0.03,t=true
,这将触发
,然后
的部分if\u0/code>(并且没有其他t=false的解决方案会导致其他选择点执行Else\u 0部分)

因此您可以删除
=/3
T=false,dif(X,Y)
,现在让我们试试:

?- cpgpartition_ts_fs_feature([c1,c2,c3],Ts,Fs,feature(at2,_,>=,10)).
Fs = [c1, c2].
很好,但是Ts在哪里

所以还有另一个bug:

如上所述,它对
Fs=[c1,c2]
每一个Ts都成功。这是因为执行满足
Fs
列表的
if\u3
Else\u 0
部分,您不限制
Ts
列表,只需将其保留为
Ts
,然后调用
cpgpartition\u Ts\u功能(Xs0,Ts0,Fs0,feature)
与另一个独立于Ts的
Ts0
列表。因此添加:

if_(memberd_t(attribute(At,AtValue3),AtList),
       (
        if_(call(Test), (Ts=[X|Ts0],Fs=Fs0), (Ts =Ts0,Fs=[X|Fs0]))
       )
       ,(Fs=[X|Fs0], Ts = Ts0 )),
                     ^^^^^^^^
                     here added 
最后,根据@false的建议,我最好将
Test=..[Op2,AtValue3,FValue],…,call(Test)
替换为
call(Op2,AtValue3,FValue)
,因为
call/N
是ISO的一部分,它适合原始的Mycroft-O'Keefe类型系统

现在让我们再试一次:

?- cpgpartition_ts_fs_feature([c1,c2,c3],Ts,Fs,feature(at2,_,>=,10)).
Ts = [c3],
Fs = [c1, c2].
似乎是正确的和决定性的:)


至于你问题的内存部分,我不太确定,但我更喜欢确定性谓词,它们不会为内存效率留下选择点。使用纯谓词将使您的编程更具关联性,并具有更好的行为,但我不确定
如果\u3
包含许多调用,那么它的内存效率是否如此高,但我不确定是否其他人可以更清楚地回答这一部分。

多亏了编码器的回答,我想出了:

cpgpartition_ts_fs_feature([],[],[],_).
cpgpartition_ts_fs_feature([X|Xs0],Ts,Fs,feature(At,_,Op,FValue)):-
    cpg_ats_i(X,AtList),
    atom_concat(#,Op,Op2), %make clpfd operator
    maplist(atterm_atname,AtList,Ats),
    if_(memberd_t(At,Ats),
      (
      memberchk(attribute(At,AtValue3),AtList),
      if_(call(Op2,AtValue3,FValue), (Ts=[X|Ts0],Fs=Fs0),
        (   Ts =Ts0,Fs=[X|Fs0]))
      ),
      (Fs=[X|Fs0],Ts=Ts0)
    ),
    cpgpartition_ts_fs_feature(Xs0,Ts0,Fs0,feature(At,_,Op,FValue)).


atterm_atname(attribute(At,_),At).

这使我能够在不改变
=/3

的定义的情况下得到相同的结果,当前建议的if_uu3;/3实现是错误的,因为 它把一个选择点放在物化上,而不是放在 如果不是这样的话。以下是一个示例缺陷:

Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.4)

?- call(','(X=Y,2=3),B).
X = Y,
B = false ;  %%% a bloody choice point %%%
B = false,
dif(X, Y). 
在这里,我们看到一个更好的智能连接 例如,SWI Prolog中CLP(FD)中的#/\。别无选择 创建点时:

Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.4)

?- X #= Y #/\ 2 #= 3 #<==> B.
B = 0,
X in inf..sup,
Y in inf..sup. 
想法是不要将任何选择点放入具体化/2, 尽量避免它们。当前(=)/3创建 一个选择点,组合时不好

条件。也许我们也可以在同样的条件下安排 在代码中的不同位置,共享相同的布尔值
指标变量。处理它…

乍一看,将
Test=…[Op2,AtValue3,FValue],…,调用(Test)
替换为
call(Op2,AtValue3,FValue)
Done。但这似乎并没有什么不同…很棒的地方!谢谢:)
Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.4)

?- call(','(X=Y,2=3),B).
X = Y,
B = false ;  %%% a bloody choice point %%%
B = false,
dif(X, Y). 
Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.4)

?- X #= Y #/\ 2 #= 3 #<==> B.
B = 0,
X in inf..sup,
Y in inf..sup. 
if(Cond, Then, Else) :-
   reify(Cond, Bool),
   thenelse(Bool, Then, Else)

thenelse(1, Then, _) :- Then.
thenelse(0, _, Else) :- Else.