Prolog中最长的子序列

时间:2015-12-24 13:00:34

标签: list prolog sequence-alignment

我想实现一个谓词P(Xs,Ys,Zs),其中XsYsZs是列表。

我是Prolog的新手,我无法找到Xs(例如。Xs = ['b','b','A','A','A','A','b','b'])中包含Ys中最长序列的方法}(例如Ys = ['A','A','A','A','c','A','A','A','A'])没有交叉 - 偶数次。也许有人已经写了这个代码,有人可以说我怎么能开始。谢谢你的帮助。

explanation of teacher.对老师的解释。

longest_subsequence(List, Part, Subsequence):-
    longest_subsequence_(List, Part, [], Subsequence).

longest_subsequence_(Xs, Ys, CurrentSubsequence, LongestSubsequence):-
    append(CurrentSubsequence, Ys, NextSubsequence),
    divide_list(Xs, [_LeftYs, NextSubsequence, _RightYs]), !,
    longest_subsequence_(Xs, Ys, NextSubsequence, LongestSubsequence).
longest_subsequence_(_Xs, _Ys, LongestSubsequence, LongestSubsequence).

3 个答案:

答案 0 :(得分:2)

我做了okey。

 main_task(Xs, Ys, Zs) :-         
      atom_chars(Xs, Xl),
      atom_chars(Ys, Yl),
      retractall(record(_, _)),
      assert(record(0, [])),
      process(Xl, Yl, Zl),
      atom_chars(Zs, Zl).

 process(Xl, Yl, _) :-     
      get_sublist(Xl, Zl),     
      length(Zl, L),
      record(MaxL, _),
      L > MaxL,
      get_index(Yl, Zl, Il),
      test_even(Il),
      test_intersect(Il, L),
      retractall(record(_, _)),
      assert(record(L, Zl)),
      fail.
    process(_, _, Zl) :-
      record(_, Zl).

    get_sublist(L1, L2) :-
      get_tail(L1, L3),
      get_head(L3, L2).

    get_tail(L, L).
    get_tail([_|T], L) :-
        get_tail(T, L).

    get_head([H|T1], [H|T2]) :-
        get_head(T1, T2).
    get_head(_, []).

    get_index(Yl, Zl, Il) :-
      get_index(Yl, Zl, Il, 0).

    get_index([], _, [], _).
    get_index([Yh|Yt], Zl, [I|It], I) :-
      get_head([Yh|Yt], Zl),
      !,
      I1 is I + 1,
      get_index(Yt, Zl, It, I1).
    get_index([_|Yt], Zl, Il, I) :-
      I1 is I + 1,
      get_index(Yt, Zl, Il, I1).

    test_even(Il) :-
      length(Il, L),
      L > 0,
      L mod 2 =:= 0.

    test_intersect([_], _).
    test_intersect([X,Y|T], L) :-
      Y - X >= L,
      test_intersect([Y|T], L).
  1. 列表中使用列表
  2. 的符号中的所有行
  3. 初始化动态数据库 - 将存储在其中,并且其最大行长
  4. 枚举来自X的所有子串(子列表).Bust进行双重“修剪” - 首先放在前面切断的列表中,然后从后面切换。
  5. 检查结果字符串的长度,如果我们已经很长,立即离开以继续破坏
  6. 我们考虑Y出现时的索引列表,然后是列表中的每个元素 - Y中的一个位置,它包含Z.
  7. 检查奇偶校验 - 只考虑索引列表的长度,chёtnaya长度 - 偶数个条目。我们需要检查它是否大于零。
  8. 检查交叉点 - 您需要检查索引列表中两个相邻元素之间的差异,差异应始终大于长度Z.
  9. 如果进行了所有检查,则会有动态数据库更新 - 当前列表Z存储为最大值
  10. 最后是强制失败,它会在第3段中回滚到分支并继续搜索。 注意:如果未执行任何检查,则此测试的失败将立即回滚到第3段中的分支并继续搜索。
  11. 当半身像结束时,执行第二个规则谓词过程,它只是选择基数中的最后一个spicok Z.
  12. 在列表的末尾,Z被转换回字符串

答案 1 :(得分:1)

一种天真的方法如下:

longest_subsequence(Xs,Ys,Zs) :-
    longest_subsequence(Xs,Ys,Ys,0,[],Zs).

longest_subsequence([X|Xs],Y0,[Y|Ys],N0,Z0,Z) :-
    try_seq([X|Xs],[Y|Ys],Nc,Zc),
    (Nc > N0
    -> longest_subsequence([X|Xs],Y0,Ys,Nc,Zc,Z)
    ;  longest_subsequence([X|Xs],Y0,Ys,N0,Z0,Z)
    ).
longest_subsequence([_|Xs],Y0,[],N0,Z0,Z) :-
    longest_subsequence(Xs,Y0,Y0,N0,Z0,Z).
longest_subsequence([],_,_,_,Z,Z).

try_seq([H|TA],[H|TB],N,[H|TC]) :-
    !,
    try_seq(TA,TB,N1,TC),
    N is N1+1.
try_seq(_,_,0,[]).

这里谓词try_seq/3旨在尽可能多地匹配(生成最长的公共子序列)从列表的开头开始。

问题在于这是一种计算成本高昂的方法:它将具有时间复杂度 O(mnp),其中 n 是第一个列表的长度, m 第二个列表的长度, p 两个列表的最小长度。

用你的例子调用它给出:

?- longest_subsequence([b,b,a,a,a],[a,a,a,c,a,a,a],Zs).
Zs = [a, a, a] ;
false.

您可以使用反向引用使算法更有效,这或多或少基于 Knuth-Morris-Pratt-algorithm

答案 2 :(得分:1)

在接近问题时,首先尝试:分而治之

当我们有list_subsequence(+List, ?Subsequence)谓词

list_subsequence([H|T], S) :-
  list_subsequence(H, T, S, _).
list_subsequence([H|T], S) :-
  list_subsequence(H, T, _, R),
  list_subsequence(R, S).

list_subsequence(H, [H|T], [H|S], R) :- !, list_subsequence(H, T, S, R).
list_subsequence(H, R, [H], R).

我们可以调用库(aggregate)帮助:

longest_subsequence(Seq, Rep, Longest) :-
  aggregate(max(L, Sub), N^(
    list_subsequence(Seq, Sub),
    aggregate(count, list_subsequence(Rep, Sub), N),
    N mod 2 =:= 0,
    length(Sub, L)
  ), max(_, Longest)).

编辑:提供更多库支持

最近添加的library有助于:

longest_subsequence_(Seq, Rep, Longest) :-
    order_by([desc(L)], filter_subsequence(Seq, Rep, Longest, L)), !.

其中filter_subsequence / 4只是外聚合的目标:

filter_subsequence(Seq, Rep, Sub, L) :-
    list_subsequence(Seq, Sub),
    aggregate(count, list_subsequence(Rep, Sub), N),
    N mod 2 =:= 0,
    length(Sub, L).