两个变量列表的交集

时间:2015-01-04 01:40:30

标签: prolog iso-prolog

如何在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仍然隐藏着这个问题。)

4 个答案:

答案 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/4include/3不是ISO,但它们的实现很简单。