1

I want to create in Prolog to find longest increasing subset of entered list. For example, you enter list of [3,1,2] and the output is [1,2],

?- subset([3,1,2], X).
X = [1,2]

I have code which shows all the subsets of this list:

subset([],[]).
subset([_|X],Y):-subset(X,Y).
subset([A|X],[A|Y]):-subset(X,Y).

Can anyone help me to find just the longest increasing subset?

Anderson
  • 11
  • 2

2 Answers2

1

Do you mean [1,3,5,6,7] to be the answer for [4,1,3,8,9,5,6,7]? IOW, do you really mean subsets, or just sublists, i.e. contiguous portions of the list?

If the latter is the case, you won't need subsets. The search is linear. If in a list [a,b,c,d,e,f] you find that d > e and the increasing sequence [a,b,c,d] stops, you don't need to restart the search from b now: the sequence will still break at d. You will just continue your search from e.

So, we'll just carry around some additional information during the search, viz. the current and the winning-so-far sub-sequences. And their lengths.

longest_incr([],0-[]).
longest_incr([A|B],RL-R):-                  % R is the result, of length RL
    longest_aux(B,[],0, [A],1, RL-R). 

longest_aux([],   Win,N, Curr,K, RL-R):- 
    ( K>N -> RL=K, reverse(Curr,R) ; RL=N, reverse(Win,R) ).
longest_aux([A|B],Win,N, Curr,K, RL-R):- Curr = [X|_], L is K,
    ( A>X -> longest_aux(B,Win, N, [A|Curr],L+1,RL-R)    % keep adding
    ; L>N -> longest_aux(B,Curr,K, [A],     1,  RL-R)    % switch the winner
    ;        longest_aux(B,Win, N, [A],     1,  RL-R)    % winner unbeaten 
    ).

If OTOH you really need the longest subset ... there's a contradiction there. A set can have its elements rearranged, so the longest subset of a given list will be

longset_subset(L,R):- sort(L,S), R=S.

Perhaps you mean the longest order-preserving sub-sequence, i.e. it is allowed to be non-contiguous. Then you can gather all solutions to your subset with findall or similar predicate, and analyze these results:

longest_subseq(L,R):- 
    findall( S, subset(L,S), X),
    maplist( longest_incr, X, Y),
    keysort( Y, Z), 
    last( Z, _Len-R).

The above has a lot of redundancy in it. We can attempt to improve its efficiency by only allowing the increasing subsequences:

incr_subseq([],[]).
incr_subseq([_|X],Y):- incr_subseq(X,Y).
incr_subseq([A|X],[A|Y]):- incr_subseq(X,Y), ( Y=[] ; Y=[B|_], A<B).

Now all the sub-sequences found by the above predicate will be increasing, so we can just take their lengths:

lenlist(List,Len-List) :- length(List,Len).
longest_subseq(L,R):- 
    findall( S, incr_subseq(L,S), X),
    maplist( lenlist, X, Y),
    keysort( Y, Z), 
    last( Z, _Len-R).

Or, the linear searching longest_incr could be tweaked for a more efficient solution. Instead of maintaining just one winning sub-sequence, it would maintain all the relevant possibilities as it goes along the input list.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • I would actually assume he means "longest increasing subsequence", based on his `subset`. There are plenty of algorithms for doing this. In his case, he could simply enumerate all increasing subsequences (that he has called subsets) and see which one is longest. –  Mar 27 '13 at 11:16
  • @Boris you mean contiguous, or non-contiguous? Based on his `subset`, perhaps the 2nd case? – Will Ness Mar 27 '13 at 11:28
  • http://en.wikipedia.org/wiki/Longest_increasing_subsequence Non-contiguous, per definition. If it were contiguous it would be called substring, I would guess . Order however is important (hence the -sequence). Plenty of available algorithms out there. –  Mar 27 '13 at 11:30
  • @Boris yes, this seems the most logical. I do mention calling `findall` there... :) – Will Ness Mar 27 '13 at 11:31
  • Maybe you could give me some example from which I could learn how to create that longest_aux predicate? As I mentioned, I am still learning Prolog – Anderson Apr 06 '13 at 09:46
0

Just out of curiosity, would it be possible in prolog to realize something like this for finding longest increasing subsequence:

  • You find all subsets of list
  • Than you find, which of these subsets are increasing
  • And then you search for the longest

If it's possible, how could I do that in Prolog?

John
  • 41
  • 2
  • 6
  • for the list `X`, the answer `R` will satisfy `sort(X,R)`. Because sets are considered equal no matter what is the order of their elements. If you mean *sub-sequences*, i.e. containing elements in original order and perhaps from non-contiguous regions of the list, then it's exactly what this question is asking. – Will Ness Apr 06 '13 at 11:46
  • I've updated my answer. I tweaked your idea BTW - I test the sub-sequences for increasing-ness as they are being generated. – Will Ness Apr 07 '13 at 16:34