Performance 在Prolog中将谓词应用于列表的子集:请求关于实现选择的建议
编辑:在我提到列出的第二个是我第一次尝试实施的项目后,我使用术语“第一次实施”和“第二次实施”时,出现了一些可以理解的混乱,因此我重新编写了相关段落。很抱歉给你带来了困惑 一些动机背景:我正在SWI Prolog中构建约束求解器,为了极大地优化空间和时间,我在主要约束数据结构中构建了反向索引。每当我的系统中的一个“变量”(不是Prolog变量)被赋值时,我想确保这个赋值不会使任何其他约束无法满足。我有一个从变量到约束的索引,可以快速选择要检查的约束。从某种意义上讲,这归结为将try_check/2谓词应用于给定的左侧(LHS)和右侧列表(RHS_L)的所有元素,其索引显示在列表(IdxL)中。以下是我当前的实现:Performance 在Prolog中将谓词应用于列表的子集:请求关于实现选择的建议,performance,list,prolog,filtering,tail-recursion,Performance,List,Prolog,Filtering,Tail Recursion,编辑:在我提到列出的第二个是我第一次尝试实施的项目后,我使用术语“第一次实施”和“第二次实施”时,出现了一些可以理解的混乱,因此我重新编写了相关段落。很抱歉给你带来了困惑 一些动机背景:我正在SWI Prolog中构建约束求解器,为了极大地优化空间和时间,我在主要约束数据结构中构建了反向索引。每当我的系统中的一个“变量”(不是Prolog变量)被赋值时,我想确保这个赋值不会使任何其他约束无法满足。我有一个从变量到约束的索引,可以快速选择要检查的约束。从某种意义上讲,这归结为将try_check/
%% FORALL Implementation
try_check_filtered(LHS, IdxL, RHS_L) :-
forall((member(Idx, IdxL), nth0(Idx, RHS_L, RHS)),
try_check(LHS, RHS)).
我还有一个早期的实现,它做了同样的事情,但是在第二个位置使用了一个额外的参数来跟踪当前的列表索引(索引列表按升序排序):
我有两个问题:
%% try_check_eni(+E1:effect, +E2:effect)
try_check_eni(E1, E2) :-
push_trying,
check_no_try,
( is_non_interfering(E1, E2)
-> (clear_try, pop_trying)
; (clear_try, pop_trying, fail))
, !.
push_-trying/0
和pop_-trying/0
断言和收回一个trying/0
谓词,该谓词稍微修改了其他一些谓词的操作方式,这样我就不必重复检查try_-check谓词时使用的代码<代码>不干扰/2不确定。在try
模式下,是非干扰的
将实例化变量标记为try/1
,以便在检查约束后清除\u try/0
可以收回实例化 nth0/3
具有线性成本。因此,与member/2
和forall/2
的组合具有二次成本。事实上,第二个代码变量没有利用索引列表按升序排列这一事实,而第一个代码变量则利用了这一事实
在开发的这个阶段,尽量不要过度优化:首先要正确执行,然后(并且只有这样)快速执行
关注清晰可读的代码,选择适当的数据结构,做出正确的库选择。。。如果环境需要,您可以用(比如)一些复合结构加上arg/3
替换列表中的随机读取访问
此外,您的代码可能会从第一个参数索引中获益。使用cut和/或assert/RECTract时要小心,这两种方法都很容易降低正确性和性能。感谢您的回复,但我意识到我的帖子不清楚。在使用术语1和2实施时,我指的是问题中列出它们的顺序,而不是我实施它们的时间顺序。所以我(仍然)很困惑,为什么二次型(forall)比线性型(tail recursive)好。我编辑了这个问题,添加了一些您要求的信息。不幸的是,代码太多,无法提供完整的实现。它是一个具有相对复杂规则的解算器,用于确定域的可满足性(如果感兴趣,请查找确定性并行java或DPJ)。我希望我提供的信息至少有点帮助。
%% try_check_eni(+E1:effect, +E2:effect)
try_check_eni(E1, E2) :-
push_trying,
check_no_try,
( is_non_interfering(E1, E2)
-> (clear_try, pop_trying)
; (clear_try, pop_trying, fail))
, !.