Extracting sequences (Lists) Prolog - prolog

Given a list eg [1,2,3,7,2,5,8,9,3,4] how would I extract the sequences within the list?
A sequence is defined as an ordered list (Normally I would say n-tuple but I have been told in prolog a tuple is referred to as a sequence). So we want to cut the list at the point where the next element is smaller than the previous one.
So for the list [1,2,3,7,2,5,8,9,3,4] it should return:
[ [1,2,3,7], [2,5,8,9], [3,4] ] %ie we have cut the list at position 4 & 8.
For this exercise you CANNOT use the construct ; or ->
Many thanks in advance!
EXAMPLE RESULTS:
eg1.
?-function([1,2,3,7,2,5,8,9,3,4],X): %so we cut the list at position 4 & 9
X = [ [1,2,3,7], [2,5,8,9], [3,4] ].
eg2.
?-function([1,2,3,2,2,3,4,3],X): %so we cut the list at position 3,4 & 8
X = [ [1,2,3], [2], [2,3,4], [3] ].
Hopefully that helps clarify the problem. If you need further clarification just let me know! Thanks again in advance for any help you are able to provide.

First, let's break it down conceptually. The predicate list_ascending_rest/3 defines a relation between a list Xs, the left-most ascending sublist of maximum length Ys, and the remaining items Rest. We will use it like in the following query:
?- Xs = [1,2,3,7,2,5,8,9,3,4], list_ascending_rest(Xs,Ys,Rest).
Ys = [1,2,3,7],
Rest = [2,5,8,9,3,4] ;
false.
The straight-forward predicate definition goes like this:
:- use_module(library(clpfd)).
list_ascending_rest([],[],[]).
list_ascending_rest([A],[A],[]).
list_ascending_rest([A1,A2|As], [A1], [A2|As]) :-
A1 #>= A2.
list_ascending_rest([A1,A2|As], [A1|Bs], Cs) :-
A1 #< A2,
list_ascending_rest([A2|As], Bs,Cs).
Then, let's implement predicate list_ascendingParts/2. This predicate repeatedly uses list_ascending_rest/3 for each part until nothing is left.
list_ascendingParts([],[]).
list_ascendingParts([A|As],[Bs|Bss]) :-
list_ascending_rest([A|As],Bs,As0),
list_ascendingParts(As0,Bss).
Example queries:
?- list_ascendingParts([1,2,3,7,2,5,8,9,3,4],Xs).
Xs = [[1,2,3,7], [2,5,8,9], [3,4]] ;
false.
?- list_ascendingParts([1,2,3,2,2,3,4,3],Xs).
Xs = [[1,2,3], [2], [2,3,4], [3]] ;
false.
Edit 2015/04/05
What if the ascending parts are known but the list is unknown? Let's find out:
?- list_ascendingParts(Ls, [[3,4,5],[4],[2,7],[5,6],[6,8],[3]]).
Ls = [3,4,5,4,2,7,5,6,6,8,3] ? ;
no
And let's not forget about the most general query using list_ascendingParts/2:
?- assert(clpfd:full_answer).
yes
?- list_ascendingParts(Ls, Ps).
Ls = [], Ps = [] ? ;
Ls = [_A], Ps = [[_A]] ? ;
Ls = [_A,_B], Ps = [[_A],[_B]], _B#=<_A, _B in inf..sup, _A in inf..sup ? ...
Edit 2015-04-27
Room for improvement? Yes, definitely!
By using the meta-predicate splitlistIfAdj/3 one can "succeed deterministically" and "use non-determinism when required", depending on the situation.
splitlistIfAdj/3 is based on if_/3 as proposed by #false in this answer. So the predicate passed to it has to obey the same convention as (=)/3 and memberd_truth/3.
So let's define (#>)/3 and (#>=)/3:
#>=(X,Y,Truth) :- X #>= Y #<==> B, =(B,1,Truth).
#>( X,Y,Truth) :- X #> Y #<==> B, =(B,1,Truth).
Let's re-ask above queries, using splitlistIfAdj(#>=)
instead of list_ascendingParts:
?- splitlistIfAdj(#>=,[1,2,3,7,2,5,8,9,3,4],Pss).
Pss = [[1,2,3,7],[2,5,8,9],[3,4]]. % succeeds deterministically
?- splitlistIfAdj(#>=,[1,2,3,2,2,3,4,3],Pss).
Pss = [[1,2,3],[2],[2,3,4],[3]]. % succeeds deterministically
?- splitlistIfAdj(#>=,Ls,[[3,4,5],[4],[2,7],[5,6],[6,8],[3]]).
Ls = [3,4,5,4,2,7,5,6,6,8,3] ; % works the other way round, too
false. % universally terminates
Last, the most general query. I wonder what the answers look like:
?- splitlistIfAdj(#>=,Ls,Pss).
Ls = Pss, Pss = [] ;
Ls = [_G28], Pss = [[_G28]] ;
Ls = [_G84,_G87], Pss = [[_G84],[_G87]], _G84#>=_G87 ;
Ls = [_G45,_G48,_G41], Pss = [[_G45],[_G48],[_G41]], _G45#>=_G48, _G48#>=_G41
% and so on...

maplist/3 as suggested in the comment won't help you here because maplist/3 is good at taking a list and mapping each element into a same-size collection of something else, or establishing a relation evenly across all of the individual elements. In this problem, you are trying to gather contiguous sublists that have certain properties.
Here's a DCG solution. The idea here is to examine the list as a series of increasing sequences where, at the boundary between them, the last element of the prior sequence is less than or equal to the first element of the following sequence (as the problem statement basically indicates).
% A set of sequences is an increasing sequence ending in X
% followed by a set of sequences that starts with a value =< X
sequences([S|[[Y|T]|L]]) --> inc_seq(S, X), sequences([[Y|T]|L]), { X >= Y }.
sequences([S]) --> inc_seq(S, _).
sequences([]) --> [].
% An increasing sequence, where M is the maximum value
inc_seq([X,Y|T], M) --> [X], inc_seq([Y|T], M), { X < Y }.
inc_seq([X], X) --> [X].
partition(L, R) :- phrase(sequences(R), L).
| ?- partition([1,2,3,4,2,3,8,7], R).
R = [[1,2,3,4],[2,3,8],[7]] ? ;
(1 ms) no
| ?- partition([1,2,3,2,2,3,4,3],X).
X = [[1,2,3],[2],[2,3,4],[3]] ? ;
(1 ms) no
The only reason for the rule sequences([]) --> []. is if you want partition([], []) to be true. Otherwise, the rule isn't required.

Related

Prolog, count how many different values there are in a list

I'm new in prolog, and I wanted to create a "function" to count how many different values I have in a list.
I've made this predicate to count the total number of values:
tamanho([],0).
tamanho([H|T],X) :- tamanho(T,X1), X is X1+1.
I wanted to follow the same line of thought like in this last predicate.(Don't know if that's possible).
So in a case where my list is [1,2,2,3], the answer would be 3.
Can someone give me a little help?
Here is a pure version which generalizes the relation. You can not only count but just see how elements have to look like in order to obtain a desired count.
In SWI, you need to install reif first.
:- use_module(library(reif),[memberd_t/3]).
:- use_module(library(clpz)). % use clpfd in SWI instead
:- op(150, fx, #). % backwards compatibility for old SWI
nt_int(false, 1).
nt_int(true, 0).
list_uniqnr([],0).
list_uniqnr([E|Es],N0) :-
#N0 #>= 0,
memberd_t(E, Es, T),
nt_int(T, I),
#N0 #= #N1 + #I,
list_uniqnr(Es,N1).
tamanho(Xs, N) :-
list_uniqnr(Xs, N).
?- tamanho([1,2,3,1], Nr).
Nr = 3.
?- tamanho([1,2,X,1], 3).
dif:dif(X,1), dif:dif(X,2).
?- tamanho([1,2,X,Y], 3).
X = 1, dif:dif(Y,1), dif:dif(Y,2)
; Y = 1, dif:dif(X,1), dif:dif(X,2)
; X = 2, dif:dif(Y,1), dif:dif(Y,2)
; Y = 2, dif:dif(X,1), dif:dif(X,2)
; X = Y, dif:dif(X,1), dif:dif(X,2)
; false.
You can fix your code by adding 1 to the result that came from the recursive call if H exists in T, otherwise, the result for [H|T] call is the same result for T call.
tamanho([],0).
tamanho([H|T], X) :- tamanho(T, X1), (member(H, T) -> X is X1; X is X1 + 1).
Tests
/*
?- tamanho([], Count).
Count = 0.
?- tamanho([1,a,21,1], Count).
Count = 3.
?- tamanho([1,2,3,1], Count).
Count = 3.
?- tamanho([1,b,2,b], Count).
Count = 3.
*/
In case the input list is always numerical, you can follow #berbs's suggestion..
sort/2 succeeds if input list has non-numerical items[1] so you can use it without any restrictions on the input list, so tamanho/2 could be just like this
tamanho(T, X) :- sort(T, TSorted), length(TSorted, X).
[1] thanks to #Will Ness for pointing me to this.

Single clause with if-the-else vs multiple clause predicates

Let's say I want to implement a predicate that 'returns' a list of all elements shared by a list of lists.
I can implement it as a one clause (looks bit ugly for logic programing):
shared_members(Members, Lists) :-
Lists = [] ->
Members = []
; findall(M, (maplist(member(M), Lists)), Members).
or as a set of clauses:
shared_members([], []). % possibly adding cut here to increase effciency
shared_members(Members, Lists) :-
findall(M, (maplist(member(M), Lists)), Members).
Which implementation is considered to be more efficient?
I know it depends on the Prolog implementation but maybe there is a general stand about efficiency of these cases.
In this case, you don't even need the first clause shared_member([], []). The findall/3 call will result in Members = [] if Lists = [].
The question is still interesting, though, and so we'll ignore this for now. You could run some stats to determine time-efficiency. Memory efficiency difference is negligible. The second approach given, however, is considered to be the canonical approach in Prolog. But they are also not equivalent in their behavior. The "if-else" in Prolog, as represented by p1 -> p2 ; p3 cuts removes the choice point after evaluation of p1. It's equivalent to p1, !, p2 ; p3.
Here's why this matters. I'll use a contrived example (which also does not require both clauses, but illustrates the point). I'll define a len/2 predicate that is true if the first argument is the length of the second:
len(0, []).
len(N, L) :- length(L, N).
Obviously, as in the case of the original problem, the first clause here is redundant, but it is important for this illustration. If I run this query, I get the following results:
| ?- len(N, [a,b,c]).
N = 3
yes
| ?- len(3, L).
L = [_,_,_]
yes
| ?- len(N, L).
L = []
N = 0 ? ;
L = []
N = 0 ? ;
L = [_]
N = 1 ? ;
L = [_,_]
N = 2 ? ;
L = [_,_,_]
N = 3 ?
Note that if both arguments are variable, it enumerates solutions. (Also, due to the redundant first clause, one of the solutions appears twice.)
Let's rewrite this predicate using "if-else":
len(N, L) :-
( L = []
-> N = 0
; length(L, N)
).
And we'll run it:
| ?- len(N, [a,b,c]).
N = 3
yes
So far, so good. But...
| ?- len(3, L).
no
| ?- len(N, L).
L = []
N = 0
yes
| ?-
Yikes! This is quite different. What happened?
In the second approach, ( L = [] -> N = 0 ; length(L, N) ) first attempts to unify L and []. If L is a variable, this succeeds with L = []. Since it succeeded, Prolog then attempts to unify N = 0. But with the query len(3, L), N is already bound to 3. So N = 0 fails and the entire clause fails.
Using the -> ; construct then, in this case, greatly reduces the generality of the implementation and yields incorrect results in some of the call scenarios.

Appending lists in prolog without repetition

I need to know how can i get all of combination of appending two lists with each other without repetition like [1,2] & [3,4] the result will be [1,3] [1,4] [2,3] [2,4]
This is the solution that does not work as desired:
(1) comb([], [], []).
(2) comb([H|T], [X|Y], [H,X]).
(3) comb([H,T|T1], [X,Y|T2], [T,Y]).
(4) comb([H|T], [X|Y], L) :-
comb(T, Y, [H|X]).
(1) says, Combining an empty list with an empty list is an empty list. This sounds logically correct.
(2) says, [H,X] is a pair of elements from [H|T] and [X|Y]. This is true (provides only one of the combinations for the solution).
(3) says, [T,Y] is a pair of elements from [H,T|T1] and [X,Y|T2]. This is also true (provides only one other combination for the solution, different to #2).
(4) says, L is a pair of elements from [H|T] and [X|Y] if [H|X] is a pair of elements from T and Y. This can't be true since L doesn't appear in the consequent of the clause, so it will never be instantiated with a value.
The above solution is over-thought and more complicated than it needs to be. It fails because it hard-codes two solutions (matching the first two elements and the second two elements). The recursive clause is then faulty since it doesn't have a logical basis, and the solution is left as a singleton variable.
To start, you need to decide what your predicate means. In this particular problem, you can think of your predicate comb(Xs, Ys, P). as being TRUE if P is a pair (say it's [X,Y]) where X is from Xs (i.e., X is a member of Xs) and Y is from Ys (Y is a member of Ys). Then, when you query your predicate, it will prompt you with each solution until all of them have been found.
This problem can be stated with one rule: [X,Y] is a combination of elements taken from Xs and Ys, respectively, if X is a member of Xs and Y is a member of Ys. That sounds like a trivially true statement, but it's all you need to solve this problem.
Translating this into Prolog gives this:
comb(Xs, Ys, [X,Y]) :- % [X,Y] is combination of elements from Xs and Ys if...
member(X, Xs), % X is a member of Xs, and
member(Y, Ys). % Y is a member of Ys
Now let's try it:
| ?- comb([1,2],[3,4],P).
P = [1,3] ? ;
P = [1,4] ? ;
P = [2,3] ? ;
P = [2,4]
(2 ms) yes
| ?-
It found all of the combinations. We let Prolog do all the work and we only had to declare what the rule was.
If you want to collect all the results in a single list, you can use a built-in predicate such as findall/3:
| ?- findall(P, comb([1,2], [3,4], P), AllP).
AllP = [[1,3],[1,4],[2,3],[2,4]]
yes
| ?-
And voilĂ . :)
You can also generalize the solution very easily and choose one element each from each list in a given list of lists. Here, multicomb/2 has as a first argument a list of lists (e.g., [[1,2], [3,4]]` and generates every combination of elements, one from each of these sublists:
multicomb([L|Ls], [X|Xs]) :-
member(X, L),
multicomb(Ls, Xs).
multicomb([], []).
Which gives:
| ?- multicomb([[1,2],[3,4]], P).
P = [1,3] ? a
P = [1,4]
P = [2,3]
P = [2,4]
yes
| ?-
And:
| ?- multicomb([[1,2],[a,b],[x,y,z]], P).
P = [1,a,x] ? a
P = [1,a,y]
P = [1,a,z]
P = [1,b,x]
P = [1,b,y]
P = [1,b,z]
...

Implement a Prolog predicate that say if an element belong to a list. Problems with not numerical lists

I am studying Prolog for an university exam and I have problems with this exercise:
Implement the predicate not_member(X,L) that is TRUE if the element X does not belong to the list L.
If my reasoning is correct, I have found a solution:
% FACT (BASE CASE): It is TRUE that X is not in the list if the list is empty.
not_member(_,[]).
% RULE (GENERAL CASE): If the list is non-empty, I can divide it in its Head
% element and the sublist Tail. X does not belong to the list if it is different
% from the current Head element and if it does not belong to the sublist Tail.
not_member(X,[Head|Tail]) :-
X =\= Head,
not_member(X,Tail).
This code works well with lists of numbers, as the following queries show:
2 ?- not_member(4, [1,2,3]).
true.
3 ?- not_member(1, [1,2,3]).
false.
With lists having some non-numerical elements, however,
it does not work and reports an error:
4 ?- not_member(a, [a,b,c]).
ERROR: =\=/2: Arithmetic: `a/0' is not a function
Why?
Let's check the documentation!
(=\=)/2 is an arithmetic operator.
+Expr1 =\= +Expr2
True if expression Expr1 evaluates to a number non-equal to Expr2.
You have to use (\=)/2 to compare two generic terms:
not_member(_, []) :- !.
not_member(X, [Head|Tail]) :-
X \= Head,
not_member(X, Tail).
and:
?- not_member(d, [a,b,c]).
true.
Use prolog-dif to get logically sound answers—for both ground and non-ground cases!
Just like in this answer, we define non_member(E,Xs) as maplist(dif(E),Xs).
Let's put maplist(dif(E),Xs) and not_member(E,Xs) by #Haile to the test!
?- not_member(E,[1,2,3]).
false. % wrong! What about `E=4`?
?- maplist(dif(E),[1,2,3]).
dif(E,1), dif(E,2), dif(E,3). % success with pending goals
Is it steadfast? (For more info on this important issue, read
this, this, this, and this answer.)
?- E=d, not_member(E,[a,b,c]).
E = d.
?- not_member(E,[a,b,c]), E=d.
false. % not steadfast
?- E=d, maplist(dif(E),[a,b,c]).
E = d.
?- maplist(dif(E),[a,b,c]), E=d. % steadfast
E = d.
Let's not forget about the most general use!
?- not_member(E,Xs).
Xs = []. % a lot of solutions are missing!
?- maplist(dif(E),Xs).
Xs = []
; Xs = [_A] , dif(E,_A)
; Xs = [_A,_B] , dif(E,_A), dif(E,_B)
; Xs = [_A,_B,_C], dif(E,_A), dif(E,_B), dif(E,_C)
...

How to represent "somewhere to the left" in prolog?

In the Prolog, how to represent the situation "somewhere to the left".
For example, there is a List "List" and two terms "X" and "Y", how to represent the rule: X is somewhere to the left of Y in the List.
This can be reduced to the problem of subsequence matching.
subsequence([], _).
subsequence([X|Sub], [X|Seq]) :-
subsequence(Sub, Seq).
subsequence(Sub, [_|Seq]) :-
subsequence(Sub, Seq).
Then your "left-of" query would be subsequence([X, Y], List), !.
You want to describe some properties of lists. Grammars are often the best way to address this.
... --> [].
... --> [_], ... .
?- Xs = "abc", phrase((...,[X], ..., [Y], ...), Xs).
Xs = "abc", X = a, Y = b
; Xs = "abc", X = a, Y = c
; Xs = "abc", X = b, Y = c
; false.
it can be done in many ways.
nth1(N,List,X) is a predicate that is true if the Nth element of the List is X.
The implementation using nth1 is pretty easy; try to solve it before you see my code.
left(X,Y,L):-
nth1(NX,L,X),
nth1(NY,L,Y),
NX<NY.
Other ways to solve it is with append/3:
left(X,Y,L):-
append(_,[X|T],L),
member(Y,L).
or just plain recursion:
left(X,Y,[X|T]):-
member(Y,T).
left(X,Y,[H|T]):-
H=\=X,
left(X,Y,T).
If you already have the append/3 predicate then you can use:
left(A,B,S) :-
append(_,[B,A|_],S).
If you ask:
?- left(1,2,[1,2,3,4]).
false.
?- left(2,1,[1,2,3,4]).
true
-Leo

Resources