Prolog - Finding the longest increasing subsequence - list

I want to solve the following exercise in Prolog:
For a list of integers Zs, max_sequence(Zs,Xs) finds a longest increasing subsequence Xs.
Sample queries:
?- max_sequence([1,2,1,2,3,4,2,1,2,1],Xs).
Xs = [1,2,3,4]. % expected result
?- max_sequence([1,2,1,2,3,4,2,1,6,7,7,2,1,8],Xs).
Xs = [1,2,3,4,6,7,8]. % expected result
I can't understand why... but my code is wrong, the result is always false.
max_sequence(L,R) :-
cresc(L,[],R).
cresc([],[],[]).
cresc([H|T],C,[H|C]) :-
maxList(H,C),
\+ member(H,C),
cresc(T,C,C).
cresc([H|T],C,C) :-
member(H,C),
cresc(T,C,C).
cresc([H|T],C,C) :-
\+ maxList(H,C),
cresc(T,C,C).
maxList(_,[]).
maxList(N, [H|T]) :-
N>H,
maxList(N,T).
I would like to know if my approach to the problem is correct.
Thanks for any help!

TL;DR: Solve problems on a high-level: Think idiomatically; and don't reinvent the wheel :)
Use clpfd!
:- use_module(library(clpfd)).
We proceed by taking the following two steps:
We start by using the meta-predicate splitlistIfAdj/3 together with (#>=)/3:
?- splitlistIfAdj(#>=,[1,2,2,2,1,2,3,4,2,1,3,5,7,1],Zss).
Zss = [[1,2],[2],[2],[1,2,3,4],[2],[1,3,5,7],[1]].
We are only interested in sublists of maximum size. max_of_by/3 can exclude all other ones:
?- max_of_by(Xs,[[1,2],[2],[2],[1,2,3,4],[2],[1,3,5,7],[1]],length).
Xs = [1,2,3,4]
; Xs = [1,3,5,7].
That's it! Let's put it together and define list_longest_ascending_sublist/2:
list_longest_ascending_sublist(Xs,Zs) :-
splitlistAdjIf(#>=,Xs,Yss),
max_of_by(Zs,Yss,length).
Sample queries:
?- list_longest_ascending_sublist([1,2,2,2,1,2,3,4,2,1,3,5,7,1],Zs).
Zs = [1,2,3,4]
; Zs = [1,3,5,7].
?- list_longest_ascending_sublist([1,2,2,3,4,5,6,2,1,2,3,4,2,1,3,5,7,1],Zs).
Zs = [2,3,4,5,6].

I can't understand your approach at all, but using Trace command in swi-prolog you can see your program execution step by step to see where it fails. Try it and you will see what's wrong with your code.
Anyway this could be one possible solution: starting from the first element of the list you should simply collect a list until elements are increasing, keeping also the length of this sublist, this is the first candidate. Then start again collecting a new list and its length, and if is longer than the candidate, you switch them, and so on..
Here you can find the code: max_seqs , the first part.

Related

mirroring a list in prolog

My wanted output is this:
?- mirror ([1,2], [] , X ).
X= [1,2,2,1]
What I have so far:
mirror(L,R,X):- L is R , [R| revertList(L,X)] .
I cant think of how this works, please help me
It is not very different from reversing a list, but how you write it is not going to work. I googled "Prolog is" and after maybe 10 seconds I see that is/2 is for arithmetic expressions. I also don't know how you think that you can put predicate but maybe it is not possible? If you want to just append then you can use append to append the mirror reversed list to the end of the original list to get the final "mirror" result:
mirror(X, Y) :- reverse(X, R), append(X, R, Y).
but this is too easy? So I wonder maybe there is more to this question? I don't know why you have three arguments when you only need two arguments? Maybe you thought that you can use an accumulator to reverse the list because to reverse a list you use accumulator like this?
list_rev(L, R) :- list_rev(L, [], R).
list_rev([], R, R).
list_rev([X|Xs], Ys, R) :-
list_rev(Xs, [X|Ys], R).
But this is very easy to google, I just googled it and found it, so maybe you googled it too and you didn't like it? To get "mirrored" you just need to keep the original list too, like so:
list_mirrored(L, M) :- list_mirrored(L, [], M).
list_mirrored([], M, M).
list_mirrored([X|Xs], Ys, [X|Zs]) :-
list_mirrored(Xs, [X|Ys], Zs).
I wasn't sure if this is correct and I googled "Prolog append" and this is how it is done.
To describe lists in Prolog, always also consider DCG notation.
For example, in this concrete case:
mirror([]) --> [].
mirror([M|Ms]) --> [M], mirror(Ms), [M].
Your test case:
?- phrase(mirror([1,2]), Ls).
Ls = [1, 2, 2, 1].
It also works in the other direction. For example:
?- phrase(mirror(Ls), [a,b,c,c,b,a]).
Ls = [a, b, c] ;
false.
The most general query yields:
?- phrase(mirror(Ls), Ms).
Ls = Ms, Ms = [] ;
Ls = [_5988],
Ms = [_5988, _5988] ;
Ls = [_5988, _6000],
Ms = [_5988, _6000, _6000, _5988] ;
Ls = [_5988, _6000, _6012],
Ms = [_5988, _6000, _6012, _6012, _6000, _5988] ;
etc.
See dcg for more information.
Note that with the definition above, we have:
?- phrase(mirror(Ls), [a,b,a]).
false.
I leave generalizing this definition (if necessary) as an easy exercise.
This would get you the desired "output":
mirror(_,_,[1,2,2,1]).
That probably won't work for most inputs, but since you haven't explained the relationship between input and output for anything but this one case, that's a good as I can do.

Sublists in Prolog(without recognizing the empty list)

I want to create a predicate in Prolog which will check if a list A is a sublist of a list B. Moreover I do not want my program to consider an empty list as a subset of another one.
E.g. included_list([1,4],[1,2,3,4,5]).
true.
included_list([2,3],[1,2,3,4,5]).
true.
included_list([1,6],[1,2,3,4,5]).
false.
included_list([],[1,2,3,4,5]).
false.
and so on...
So, I have written the following code so far:
member(X,[X|Tail]).
member(X,[Head|Tail]):- member(X,Tail).
included_list([X],_).
included_list([Head|Tail],List):- member(Head,List), included_list(Tail,List).
But the above code seems to be wrong, because in one specific case it throws true, instead of throwing wrong. I wish I'd made it clear having presented the following screenshot:
As you might have noticed the fifth(5th) sentence gives true, instead of wrong. That is, when I write a sentence of the form:
included_list([x,y],[w,x,v,z]).
whereas only x is included in the second list(and not y) the program gives me true(and this is wrong).
In general, if the first argument of the first list is included in the second list then, no matter if the rest of the former are included in the latter, the program gives me true.
In any other case the program gives me the right result(true or false).
What do I do wrong?
I will be waiting for your answers!
Thank you in advance!
Your problem is the first clause of included_list/2. This:
included_list([X], _).
What does it mean? It means, "If the first argument is a list with one element, succeed, ignoring the second argument."
A short aside: if you would not ignore compiler warnings, you would have caught this mistake already. You should get a loud and clear "Singleton variable" warning, hinting that the code you have written does not do what you think it does.
What you actually mean is more along the lines of:
subset_list([X|Xs], Ys) :-
subset_list_1(Xs, X, Ys).
subset_list_1([], X, Ys) :-
member(X, Ys).
subset_list_1([X|Xs], X0, Ys) :-
member(X0, Ys),
subset_list_1(Xs, X, Ys).
But I don't know why you don't simply use the available subset/2, and simply add a requirement that the subset is not an empty list:
subset_list(Subset, List) :-
Subset = [_|_], % a list with at least one element
subset(Subset, List).
Despite what the documentation claims, the second argument to subset/2 does not have to be a true "set", but it does expect that both lists are ground (do not contain any free variables). You can see the source code here.
In this answer we let meta-predicate maplist/2 handle recursion and define:
all_included(Sub, Es) :-
same_length(Es, Xs),
Sub = [_|_], % minimum length: 1
append(_, Sub, Xs), % maximum length: as long as `Es`
maplist(list_member(Es), Sub).
Let's run the queries the OP gave!
First up, use-cases we expect to succeed:
?- member(Xs, [[1,4],[2,3],[2,3,5],[3,4]]), all_included(Xs, [1,2,3,4,5]).
Xs = [1,4]
; Xs = [2,3]
; Xs = [2,3,5]
; Xs = [3,4]
; false.
Next up, some use-cases we expect to fail:
?- member(Xs, [[],[2,6],[1,6]]), all_included(Xs, [1,2,3,4,5]).
false.
?- all_included([3,5], [1,2,5]).
false.

Populate a list with only one occurrence of multiple list elements

I'm new to Prolog and I am trying to understand it.
I started with some simple program, this one should:
check if an element is contained in the rest of the list
if FALSE do nothing
if TRUE add it to a second list. (only one occurrence of a char should be added to the second list).
Some examples with expected results:
?- occ([a,b,c,a,a,b,e,f,g], Y).
Y = [a,b].
?- occ([a,a,a,a,a], Y).
Y = [a].
?- occ([a,b,c,d,e,f,g], Y).
Y = [].
Here's the code I wrote, but I have some problems (it always returns true).
occ([],[]).
occ([],_Y).
occ([X|Xs],[X|Y]) :-
occ(Xs,Y),
member(X,Xs),
not(member(X,Y)),
!.
occ([_X|_Xs],_Y).
I tried using the debugger and I found that the not(member(X,Y)) is always false and in the binding section there is only X and Xs and never Y. Any advice is much appreciated! Thank you.
UPDATE
I think I solved it, here's the code:
occ([],[]).
occ([X|Xs],[X|Y]) :-
occ(Xs,Y),
member(X,Xs),
not(member(X,Y)),
!.
occ([_X|_Xs],[]).
But I'm not really sure why it works now... in the 3-th occ I changed the _Y with []..
But why does it change the results?
In this answer we use meta-predicate tpartition/4 in combination with if_/3 and (=)/3.
We define list_duplicateset/2 like this:
list_duplicateset([], []).
list_duplicateset([E|Xs0], Ys0) :-
tpartition(=(E), Xs0, Es, Xs),
if_(Es = [],
Ys0 = Ys,
Ys0 = [E|Ys]),
list_duplicateset(Xs, Ys).
First, we run a sample query taken from this answer to a similar question:
?- list_duplicateset([1,2,2,3,4,5,7,6,7], Xs).
Xs = [2,7].
Next, let's run the queries the OP gave:
?- list_duplicateset([a,b,c,a,a,b,e,f,g], Xs).
Xs = [a, b].
?- list_duplicateset([a,a,a,a,a], Xs).
Xs = [a].
?- list_duplicateset([a,b,c,d,e,f,g], Xs).
Xs = [].
Note that all queries presented above
give the expected answers and succeed deterministically.

Removing heads from lists in Prolog

I'm trying to write a predicate to remove the head from every list in list of lists and add the tails to a new list. The resulting list should be returned as the second parameter.
Here's the attempt:
construct_new(S,New) :-
New = [],
new_situation(S,New).
new_situation([],_).
new_situation([H|T], New) :-
chop(H, H1),
new_situation(T, [H1|New]).
chop([_|T], T).
You would call it like this:
construct_new([[x,x],[b,c],[d,e,f]],S).
This, however, only produces output true..
Step-by-step execution
Your query is construct_new(Input,Output), for some instanciated Input list.
The first statement in construct_new/2 unifies Output (a.k.a. New) with the empty list. Where is the returned list supposed to be available for the caller? Both arguments are now unified.
You call new_situation(Input,[])
You match the second clause new_situation([H|T],[]), which performs its task recursively (step 4, ...), until ...
You reach new_situation([],_), which successfully discards the intermediate list you built.
Solutions
Write a simple recursive predicate:
new_situation([],[]).
new_situation([[_|L]|T],[L|R]) :-
new_situation(T,R).
Use maplist:
construct_new(S,R) :-
maplist(chop,S,R).
Remark
As pointed out by other answers and comments, your predicates are badly named. construct_new is not a relation, but an action, and could be used to represent almost anything. I tend to like chop because it clearly conveys the act of beheading, but this is not an appropriate name for a relation. repeat's list_head_tail(L,H,T) is declarative and associates variables to their roles. When using maplist, the other predicate (new_situation) doesn't even need to exist...
...even though guillotine/3 is tempting.
This could be done with a DCG:
owth(Lists, Tails) :-
phrase(tails(Tails), Lists).
tails([]) --> [].
tails([T|Tails]) --> [[_|T]], tails(Tails).
Yielding these queries:
| ?- owth([[x,x],[b,c],[d,e,f]], T).
T = [[x],[c],[e,f]] ? ;
no
| ?- owth(L, [[x],[c],[e,f]]).
L = [[_,x],[_,c],[_,e,f]]
yes
(owth = Off with their heads! or, if used the other direction, On with their heads!)
If you also want to capture the heads, you can enhance it as follows:
owth(Lists, Heads, Tails) :-
phrase(tails(Heads, Tails), Lists).
tails([], []) --> [].
tails([H|Hs], [T|Tails]) --> [[H|T]], tails(Hs, Tails).
We use meta-predicate maplist/[3-4] with one of these following auxiliary predicates:
list_tail([_|Xs],Xs).
list_head_tail([X|Xs],X,Xs).
Let's run some queries!
?- maplist(list_head_tail,[[x,x],[b,c],[d,e,f]],Heads,Tails).
Heads = [x,b,d],
Tails = [[x],[c],[e,f]].
If you are only interested in the tails, use maplist/4 together with list_head_tail/3 ...
?- maplist(list_head_tail,[[x,x],[b,c],[d,e,f]],_,Tails).
Tails = [[x],[c],[e,f]].
... or, even simpler, maplist/3 in tandem with list_tail/2:
?- maplist(list_tail,[[x,x],[b,c],[d,e,f]],Tails).
Tails = [[x],[c],[e,f]].
You can also use the somewhat ugly one-liner with findall/3:
?- L = [[x,x],[b,c],[d,e,f]],
findall(T, ( member(M, L), append([_], T, M) ), R).
R = [[x], [c], [e, f]].
(OK, technically a two-liner. Either way, you don't even need to define a helper predicate.)
But definitely prefer the maplist solution that uses chop as shown above.
If you do the maplist expansion by hand, and name your chop/2 a bit better, you would get:
lists_tails([], []).
lists_tails([X|Xs], [T|Ts]) :-
list_tail(X, T),
lists_tails(Xs, Ts).
And since you can do unification in the head of the predicate, you can transform this to:
lists_tails([], []).
lists_tails([[_|T]|Xs], [T|Ts]) :-
lists_tails(Xs, Ts).
But this is identical to what you have in the other answer.
Exercise: why can't we say:
?- maplist(append([_]), R, [[x,x],[b,c],[d,e,f]]).

How do I check if the first occurrence of a number equals to x?

I'm am trying to find a way to check if the first first a number in a nested list equals to x.
check(X,L), X= is a number and Y is a nested list.
check(2,[a,b[g,4],y,8]).
false
check(2,[a,b[g,2],y,8]).
true
It seems that recursion would do best. But I still do not understand how to approach it with recursion in Prolog.
I had this idea of flattening the nested list and then check if first element is a number and if it equals to X.
Can anyone help me?
Your idea must be refined. Some code is needed to match the first occurrence. I would 'cheat':
check(X,L) :- flatten(L,F), include(number,F,[X|_]).
It can be nicely done with simple recursion:
check(X,[X|_]) :- number(X).
check(X,[NL|_]) :- is_list(NL), check(X, NL).
check(X,[V|L]) :- not(number(V)), check(X, L).
UPDATE:
This fixes problem found by #CappelliC:
check(X,[X|_]) :- number(X).
check(X,[V|L]) :- not(number(V)), not(is_list(V)), check(X, L).
check(X,[NL|L]) :- is_list(NL), append(NL,L,BL), check(X, BL).
Results:
?- check(2,[a,b,[g,4],y,8]).
false.
?- check(2,[a,b,[g,2],y,8]).
true .