2

I want to implement a predicate P(Xs,Ys,Zs) where Xs,Ys,Zs are lists.

I'm new in Prolog and I can't find a way to get to the longest sequence in Xs (example. Xs = ['b','b','A','A','A','A','b','b']) which is included to Ys (for example Ys = ['A','A','A','A','c','A','A','A','A']) without crossing- an even number of times. Maybe someone already wrote this code ore some one can say me how can I start. Thanks for helps.

explanation of teacher. 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).
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
aydo000
  • 37
  • 4
  • please give few concrete example calls and their intended results, as well as what your code produces and why is it wrong. without it it's unclear what you're asking. – Will Ness Dec 24 '15 at 13:24
  • @WillNess excuse me. i speak very bad english) results will be like this. longest_subsequence ([b,b,a,a,a],[a,a,a,c,a,a,a],[Zs]). Zs=[aaa] if 2.4.6.8 times its okey. ELSE longest_subsequence ([b,b,a,a,a],[a,a,a,c,a,a,a.c.a.a.a],[Zs]). Zs=[aaa] NOT OKEY. – aydo000 Dec 24 '15 at 14:47
  • You can solve this problem more efficiently using *dynamic programming*... – Willem Van Onsem Dec 24 '15 at 21:55
  • There is a fundamental terminological confusion here: There are [common subsequences](https://en.wikipedia.org/wiki/Longest_common_subsequence_problem) and [common substrings](https://en.wikipedia.org/wiki/Longest_common_substring_problem). You certainly mean substring not subsequence! – false Dec 31 '15 at 19:43

3 Answers3

2

okey i did.

 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. All lines in the list at the symbols on working with lists
  2. Initialize the dynamic database - will be stored in it, and its maximum line length
  3. enumerates all of the substring (sublists) from X. Bust goes double "pruning" - first place in a list of cut off the front, then from behind.
  4. Check the length of the resulting string, if we already have a long, immediately leave for the continuation of busting
  5. We consider a list of indexes in the occurrence of a Y, then there is every element of the list - a position in the Y, from which it includes Z.
  6. Check the parity - just consider the length of the list of indexes, chёtnaya length - an even number of entries. And we need to check that it is greater than zero.
  7. Check the intersection - you need to check the difference between two adjacent elements of the list of indexes, the difference should always be greater than the length Z.
  8. If all checks are made, there is a dynamic database updates - current list Z is stored as the maximum
  9. At the end it is a forced failure, it is rolled back to the fork in paragraph 3) and the continued search. Note: If any check is not performed, the failure of this test is immediately rolled back to the fork in paragraph 3) and the continued search.
  10. When the bust comes to an end, performed a second rule predicate process, it simply selects the last spicok Z in the base.
  11. At the end of the list Z is converted back to a string
false
  • 10,264
  • 13
  • 101
  • 209
aydo000
  • 37
  • 4
1

A naive approach is the following:

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,[]).

here a predicate try_seq/3 aims to match as much as possible (generate the longest common subsequence) starting from the beginning of the list.

The problem is that this is a computationally expensive approach: it will have a time complexity O(m n p) with n the length of the first list, m the length of the second list and p the minimum length of the two lists.

Calling this with your example gives:

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

You can make the algorithm more efficient using back-referencing, this is more or less based on the Knuth-Morris-Pratt-algorithm.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
1

When approaching a problem, first try: divide and conquer.

When we have a list_subsequence(+List, ?Subsequence) predicate

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).

we can call for library(aggregate) help:

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)).

edit: more library support available

A recently added library helps:

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

where filter_subsequence/4 is simply the goal of the outer aggregate:

filter_subsequence(Seq, Rep, Sub, L) :-
    list_subsequence(Seq, Sub),
    aggregate(count, list_subsequence(Rep, Sub), N),
    N mod 2 =:= 0,
    length(Sub, L).
CapelliC
  • 59,646
  • 5
  • 47
  • 90