如何在ISO Prolog中定义一个(元逻辑)谓词,用于在线性时间内运行的两个变量列表的交集?变量可以按任何确定的顺序出现。没有像变量“年龄”这样的依赖于实现的属性必须影响结果。
与library(ordsets)
类似,我们称之为关系varset_intersection(As, Bs, As_cap_Bs).
?- varset_intersection([A,B], [C,D], []).
true.
?-varset_intersection([A,B], [B,A], []).
false.
?- varset_intersection([A,B,C], [C,A,D], Inter).
Inter = [A,C].
or
Inter = [C,A].
?- varset_intersection([A,B],[A,B],[A,C]).
B = C
or
A = B, A = C
?- varset_intersection([A,B,C],[A,B],[A,C]).
idem
也就是说,第三个参数是一个输出参数,它与前两个参数的交集结合。
从当前的ISO标准(ISO / IEC 13211-1:1995,包括list of the built-ins)中查看此Cor.2。
(请注意,几年前我在另一个问题中回答了这个问题。然而,Google仍然隐藏着这个问题。)
答案 0 :(得分:3)
如果term_variables/2
的工作时间与第一个参数的大小呈线性关系,则可能会有效:
varset_intersection(As, Bs, As_cap_Bs):-
term_variables([As, Bs], As_and_Bs),
term_variables(As, SetAs),
append(SetAs, OnlyBs, As_and_Bs),
term_variables([OnlyBs, Bs], SetBs),
append(OnlyBs, As_cap_Bs, SetBs).
每个公共变量在结果列表中只出现一次,无论它出现在两个给定列表中的次数。
?- varset_intersection2([A,_C,A,A,A], [A,_B,A,A,A], L).
L = [A].
此外,它可能会产生奇怪的结果,如下所示:
?- varset_intersection([A,_X,B,C], [B,C,_Y,A], [C, A, B]).
A = B, B = C.
(permutation/2
可能会有所帮助。)
答案 1 :(得分:2)
如果copy_term/2
使用线性时间,我相信以下工作:
varset_intersection(As, Bs, Cs) :-
copy_term(As-Bs, CopyAs-CopyBs),
ground_list(CopyAs),
select_grounded(CopyBs, Bs, Cs).
ground_list([]).
ground_list([a|Xs]) :-
ground_list(Xs).
select_grounded([], [], []).
select_grounded([X|Xs], [_|Bs], Cs) :-
var(X),
!,
select_grounded(Xs, Bs, Cs).
select_grounded([_|Xs], [B|Bs], [B|Cs]) :-
select_grounded(Xs, Bs, Cs).
我们的想法是在一次调用中将两个列表复制到copy_term/2
以保留它们之间的共享变量,然后将第一个副本的变量接地,然后选择与基础位置对应的第二个列表的原始变量第二份副本。
答案 2 :(得分:1)
如果unify_with_occurs_check(Var, ListOfVars)
在一段时间内失败或成功,则此实现应在线性时间内产生答案:
filter_vars([], _, Acc, Acc).
filter_vars([A|As], Bs, Acc, As_cap_Bs):-
(
\+ unify_with_occurs_check(A, Bs)
->
filter_vars(As, Bs, [A|Acc], As_cap_Bs)
;
filter_vars(As, Bs, Acc, As_cap_Bs)
).
varset_intersection(As, Bs, As_cap_Bs):-
filter_vars(As, Bs, [], Inter),
permutation(Inter, As_cap_Bs).
当给定列表包含重复项时,此实现存在问题:
?- varset_intersection1([A,A,A,A,B], [B,A], L).
L = [B, A, A, A, A] ;
?- varset_intersection1([B,A], [A,A,A,A,B], L).
L = [A, B] ;
已编辑:将bagof/3
更改为手动编写的过滤器,感谢@false在下面的评论中观察。
答案 3 :(得分:0)
可能的解决方案是使用Bloom filter。如果发生碰撞,结果可能是错误的,但存在具有更好碰撞阻力的功能。这是一个使用单个哈希函数的实现。
sum_codes([], _, Sum, Sum).
sum_codes([Head|Tail], K, Acc,Sum):-
Acc1 is Head * (256 ** K) + Acc,
K1 is (K + 1) mod 4,
sum_codes(Tail, K1, Acc1, Sum).
hash_func(Var, HashValue):-
with_output_to(atom(A), write(Var)),
atom_codes(A, Codes),
sum_codes(Codes, 0, 0, Sum),
HashValue is Sum mod 1024.
add_to_bitarray(Var, BAIn, BAOut):-
hash_func(Var, HashValue),
BAOut is BAIn \/ (1 << HashValue).
bitarray_contains(BA, Var):-
hash_func(Var, HashValue),
R is BA /\ (1 << HashValue),
R > 0.
varset_intersection(As, Bs, As_cap_Bs):-
foldl(add_to_bitarray, As, 0, BA),
include(bitarray_contains(BA), Bs, As_cap_Bs).
我知道foldl/4
和include/3
不是ISO,但它们的实现很简单。