Making a list from a tuple - prolog

I am trying to make a list from a tuple of variable size. However, I am having trouble figuring out how to represent an empty tuple (or a tuple with a single value in it), which I need as my end case.
This is what I have right now which, judging by the trace, does create a list (reversed however but it's not really a problem) but it fails at the very end.
tuple_to_list((), []).
tuple_to_list((X, ()), [X]).
tuple_to_list((X, XS), List) :-
tuple_to_list(XS, [X|List]).

Just :
tuple_to_list((X, XS),[X | List]) :-
tuple_to_list(XS, List).
tuple_to_list((X), [X]):-
X \= (_,_).
Last clause X \= (,). because of
?- (X) = (a,b).
X = (a, b).

Related

adjacent involving first and last element, Prolog

HI I would like to know how a method that finds out if two members of a list in Prolog are adjacent as the catch is that the first and the last elements are checked if they are adjacent something like
(b,c,[b,a,d,c])
would give yes they are adjacent. I already have this code
adjacent(X, Y, [X,Y|_]).
adjacent(X, Y, [_|Tail]) :-
adjacent(X, Y, Tail).
but I do not know how to include the head of the list and the last elments as well being compared for being adjacent. If you are really good maybe you can tell me also how it is possible to make something like this
(c,b,[a,b,c,d])
to be true I mean the elements are adjacent no matter which exactly is first.
You can make use of last/2 predicate [swi-doc] to obtain the last element of the list. But you can not use this in the recursive call, since otherwise it will each element in the list pair with the last element as well.
The trick is to make a helper predicate for the recursive part, and then make the adjacent/3 predicate to call the recursive one you wrote yourself, or one where we match with the last element:
adjacent(X, Y, L) :-
adj(X, Y, L).
adjacent(X, Y, [Y|T]) :-
last(T, X).
adj(X, Y, [X,Y|_]).
adj(X, Y, [_|T]) :-
adj(X, Y, T).
Relations about lists can often be described with a Definite Clause Grammar dcg.
A first attempt might be:
adjacent(A, B, L) :-
phrase(adjacent(A, B), L). % interface to DCG
adjacent(A,B) -->
..., ( [A,B] | [B,A] ), ... .
... --> [] | [_], ... .
Yet, this leaves out cases like adjacent(a,d,[a,b,c,d]). One possibility would be to add another rule, or maybe simply extend the list to be considered.
adjacent(A, B, L) :-
L = [E,_|_],
append(L, [E], M),
phrase(adjacent(A, B), L).

Compare and remove elements from list

So i want to make a program that, given a list and an element, returns only the list until said element appears,like this:
propaga( [(1,1),(1,2),(1,3),(1,4)],(1,3),L).
L = [(1,1),(1,2),(1,3)].
Currently i have this:
adiciona((X,Y),[],[(X,Y)]).
adiciona((X,Y), [(W,Z)|Tail],[(W,Z)|Tail1]):-
adiciona((X,Y),Tail,Tail1).
propaga_aux([X|_], X, [X]).
propaga_aux([(X,Y)|_], (Z,W), P):-
(X,Y) = (Z,W), !,
adiciona((X,Y),[],P).
propaga_aux([(X,Y)|T], (Z,W), P):-
(X,Y) \= (Z,W), !,
adiciona((X,Y),[],P),
propaga_aux(T, (Z,W), P).
Adiciona adds an element to the end of a list.
It keeps returning false, i think the problem is how i use the predicate adiciona but i can't figure out what i'm doing wrong, i have tried a lot of variations and i can't get this right, can someone help me?
Your predicate adiciona works correctly.
However note that you don't necessarily need to repeat the term (A,B) everywhere. If you put a single variable in place of that it will work the same way, and it will be more generic.
The problem is the other predicate: I would make it this way:
when you haven't found the matching item yet, the items are copied to the output list recursively;
when the matching item is found, the output list is composed only of that element, and recursion will stop.
At this point you realize that the predicate adiciona is not needed to solve this problem.
Prolog code:
propaga([X|Xs], Z, [X|Ys]) :- X \= Z, propaga(Xs, Z, Ys).
propaga([X|_], X, [X]).
Test:
?- propaga( [(1,1),(1,2),(1,3),(1,4)],(1,3),L).
L = [(1, 1), (1, 2), (1, 3)] ;
false.

Prolog - count occurrence of number

I want to write predicate which can count all encountered number:
count(1, [1,0,0,1,0], X).
X = 2.
I tried to write it like:
count(_, [], 0).
count(Num, [H|T], X) :- count(Num, T, X1), Num = H, X is X1 + 1.
Why doesn't work it?
Why doesn't work it?
Prolog is a programming language that often can answer such question directly. Look how I tried out your definition starting with your failing query:
?- count(1, [1,0,0,1,0], X).
false.
?- count(1, Xs, X).
Xs = [], X = 0
; Xs = [1], X = 1
; Xs = [1,1], X = 2
; Xs = [1,1,1], X = 3
; ... .
?- Xs = [_,_,_], count(1, Xs, X).
Xs = [1,1,1], X = 3.
So first I realized that the query does not work at all, then I generalized the query. I replaced the big list by a variable Xs and said: Prolog, fill in the blanks for me! And Prolog did this and reveals us precisely the cases when it will succeed.
In fact, it only succeeds with lists of 1s only. That is odd. Your definition is too restricted - it correctly counts the 1s in lists where there are only ones, but all other lists are rejected. #coder showed you how to extend your definition.
Here is another one using library(reif) for
SICStus|SWI. Alternatively, see tfilter/3.
count(X, Xs, N) :-
tfilter(=(X), Xs, Ys),
length(Ys, N).
A definition more in the style of the other definitions:
count(_, [], 0).
count(E, [X|Xs], N0) :-
if_(E = X, C = 1, C = 0),
count(E, Xs, N1),
N0 is N1+C.
And now for some more general uses:
How does a four element list look like that has 3 times a 1 in it?
?- length(L, 4), count(1, L, 3).
L = [1,1,1,_A], dif(1,_A)
; L = [1,1,_A,1], dif(1,_A)
; L = [1,_A,1,1], dif(1,_A)
; L = [_A,1,1,1], dif(1,_A)
; false.
So the remaining element must be something different from 1.
That's the fine generality Prolog offers us.
The problem is that as stated by #lurker if condition (or better unification) fails then the predicate will fail. You could make another clause for this purpose, using dif/2 which is pure and defined in the iso:
count(_, [], 0).
count(Num, [H|T], X) :- dif(Num,H), count(Num, T, X).
count(Num, [H|T], X) :- Num = H, count(Num, T, X1), X is X1 + 1.
The above is not the most efficient solution since it leaves many choice points but it is a quick and correct solution.
You simply let the predicate fail at the unification Num = X. Basically, it's like you don't accept terms which are different from the only one you are counting.
I propose to you this simple solution which uses tail recursion and scans the list in linear time. Despite the length, it's very efficient and elegant, it exploits declarative programming techniques and the backtracking of the Prolog engine.
count(C, L, R) :-
count(C, L, 0, R).
count(_, [], Acc, Acc).
count(C, [C|Xr], Acc, R) :-
IncAcc is Acc + 1,
count(C, Xr, IncAcc, R).
count(C, [X|Xr], Acc, R) :-
dif(X, C),
count(C, Xr, Acc, R).
count/3 is the launcher predicate. It takes the term to count, the list and gives to you the result value.
The first count/4 is the basic case of the recursion.
The second count/4 is executed when the head of the list is unified with the term you are looking for.
The third count/4 is reached upon backtracking: If the term doesn’t match, the unification fails, you won't need to increment the accumulator.
Acc allows you to scan the entire list propagating the partial result of the recursive processing. At the end you simply have to return it.
I solved it myself:
count(_, [], 0).
count(Num, [H|T], X) :- Num \= H, count(Num, T, X).
count(Num, [H|T], X) :- Num = H, count(Num, T, X1), X is X1 + 1.
I have decided to add my solution to the list here.
Other solutions here use either explicit unification/failure to unify, or libraries/other functions, but mine uses cuts and implicit unification instead. Note my solution is similar to Ilario's solution but simplifies this using cuts.
count(_, [], 0) :- !.
count(Value, [Value|Tail],Occurrences) :- !,
count(Value,Tail,TailOcc),
Occurrences is TailOcc+1.
count(Value, [_|Tail], Occurrences) :- count(Value,Tail,Occurrences).
How does this work? And how did you code it?
It is often useful to equate solving a problem like this to solving a proof by induction, with a base case, and then a inductive step which shows how to reduce the problem down.
Line 1 - base case
Line 1 (count(_, [], 0) :- !.) handles the "base case".
As we are working on a list, and have to look at each element, the simplest case is zero elements ([]). Therefore, we want a list with zero elements to have no instances of the Value we are looking for.
Note I have replaced Value in the final code with _ - this is because we do not care what value we are looking for if there are no values in the list anyway! Therefore, to avoid a singleton variable we negate it here.
I also added a ! (a cut) after this - as there is only one correct value for the number of occurrences we do not want Prolog to backtrack and fail - therefore we tell Prolog we found the correct value by adding this cut.
Lines 2/3 - inductive step
Lines 2 and 3 handle the "inductive step". This should handle if we have one or more elements in the list we are given. In Prolog we can only directly look at the head of the list, therefore let us look at one element at a time. Therefore, we have two cases - either the value at the head of the list is the Value we are looking for, or it is not.
Line 2
Line 2 (count(Value, [Value|Tail],Occurrences) :- !, count(Value,Tail,TailOcc), Occurrences is TailOcc+1.) handles if the head of our list and the value we are looking for match. Therefore, we simply use the same variable name so Prolog will unify them.
A cut is used as the first step in our solution (which makes each case mutually exclusive, and makes our solution last-call-optimised, by telling Prolog not to try any other rules).
Then, we find out how many instances of our term there are in the rest of the list (call it TailOcc). We don't know how many terms there are in the list we have at the moment, but we know it is one more than there are in the rest of the list (as we have a match).
Once we know how many instances there are in the rest of the list (call this Tail), we can take this value and add 1 to it, then return this as the last value in our count function (call this Occurences).
Line 3
Line 3 (count(Value, [_|Tail], Occurrences) :- count(Value,Tail,Occurrences).) handles if the head of our list and the value we are looking for do not match.
As we used a cut in line 2, this line will only be tried if line 2 fails (i.e. there is no match).
We simply take the number of instances in the rest of the list (the tail) and return this same value without editing it.

check if element is repeated in list in prolog

multi_available(X):-
member(X,
[grilled_chicken,
jambo_beef,
grilled_cheese_sandwich,roast_beef,potato_salad,chicken_rice,
jambo_beef,
service_dish,service_dish,
beef_stew,potato_corn,grilled_chicken,roast_beef,mushroom_rice,
service_dish,
jambo_beef]).
member(X,[X|_]).
member(X,[_|T]):-member(X,T).
How can I check if an element is repeated in a list in Prolog?
Using Prologue of Prolog:
member(X, L) is true if X is an element of the list L.
select(X, Xs, Ys) is true if X is an element of the
list Xs and Ys is the list Xs with one occurrence of X removed.
I get the following simple solution:
:- use_module(library(basic/lists)).
multi_available(L, X) :- select(X, L, R), member(X, R).
It might not be the most efficient. But it works:
Jekejeke Prolog 2, Runtime Library 1.2.5
(c) 1985-2017, XLOG Technologies GmbH, Switzerland
?- multi_available([a,b,c,b,a,d],X).
X = a ;
X = b ;
X = b ;
X = a ;
No
I'm not sure if you just want to know whether an element occurs more than once or whether you need how many times it occurs, so here's both!
See if the List contains Element, +1 to Count for every occurrence
occurrences(Element,[Head|Tail], Count, OutputCount) :-
Element = Head,
NewCount is Count + 1,
occurrences(Element, Tail, NewCount, OutputCount).
Element does not match the first element of the List? Don't add 1, go to the next element.
occurrences(Element, [Head|Tail], Count, OutputCount) :-
Element \= Head,
occurrences(Element, Tail, Count, OutputCount).
If the List is empty, return the final count
occurrences(Element,[],Count,Count).
Since the Count can't be negative, just pass it on as Zero and only return the result.
occurrences(Element, List, Count) :- occurrences(Element, List, 0, Count).
Check whether the result is higher than 1
moreThanOnce(Element, List) :-
occurrences(Element, List, Count),
Count > 1.
Does Element occur more than once in List?
?- moreThanOnce(1, [1,2,3,1,1,1]).
How many times does it occur?
?- occurrences(1, [1,2,3,1,1,1], Count).
Note that if a list is empty, [Head|Tail] will automatically fail and List = [] automatically succeeds. This means that OutputCount remains empty throughout the program, UNTIL the end condition is met, which is only reached after [Head|Tail] fails, meaning the list is empty. I hope this is clear enough, be sure to ask for clarifications if it isn't.

How to check if a list is a non-empty sublist of another list in Prolog

I am trying to create an included_list(X,Y) term that checks if X is a non-empty sublist of Y.
I already use this for checking if the elements exist on the Y list
check_x(X,[X|Tail]).
check_x(X,[Head|Tail]):- check_x(X,Tail).
And the append term
append([], L, L).
append([X | L1], L2, [X | L3]) :- append(L1, L2, L3).
to create a list, in order for the program to finish on
included_list([HeadX|TailX],[HeadX|TailX]).
but I am having problems handling the new empty list that I am trying to create through "append" (I want to create an empty list to add elements that are confirmed to exist on both lists.)
I have found this
sublist1( [], _ ).
sublist1( [X|XS], [X|XSS] ) :- sublist1( XS, XSS ).
sublist1( [X|XS], [_|XSS] ) :- sublist1( [X|XS], XSS ).
but it turns true on sublist([],[1,2,3,4)
Since you're looking for a non-contiguous sublist or ordered subset, and not wanting to include the empty list, then:
sub_list([X], [X|_]).
sub_list([X], [Y|T]) :-
X \== Y,
sub_list([X], T).
sub_list([X,Y|T1], [X|T2]) :-
sub_list([Y|T1], T2).
sub_list([X,Y|T1], [Z|T2]) :-
X \== Z,
sub_list([X,Y|T1], T2).
Some results:
| ?- sub_list([1,4], [1,2,3,4]).
true ? a
no
| ?- sub_list(X, [1,2,3]).
X = [1] ? a
X = [2]
X = [3]
X = [1,2]
X = [1,3]
X = [1,2,3]
X = [2,3]
(2 ms) no
| ?- sub_list([1,X], [1,2,3,4]).
X = 2 ? a
X = 3
X = 4
(2 ms) no
Note that it doesn't just tell you if one list is a sublist of another, but it answers more general questions of, for example, What are the sublists of L? When cuts are used in predicates, it can remove possible valid solutions in that case. So this solution avoids the use of cut for this reason.
Explanation:
The idea is to generate a set of rules which define what a sublist is and try to do so without being procedural or imperative. The above clauses can be interpreted as:
[X] is a sublist of the list [X|_]
[X] is a sublist of the list [Y|T] if X and Y are different and [X] is a sublist of the list T. The condition of X and Y different prevents this rule from overlapping with rule #1 and greatly reduces the number of inferences required to execute the query by avoiding unnecessary recursions.
[X,Y|T1] is a sublist of [X|T2] if [Y|T1] is a sublist of T2. The form [X,Y|T1] ensures that the list has at least two elements so as not to overlap with rule #1 (which can result in any single solution being repeated more than once).
[X,Y|T1] is a sublist of [Z|T2] if X and Z are different and [X,Y|T1] is a sublist of T2. The form [X,Y|T1] ensures that the list has at least two elements so as not to overlap with rule #2, and the condition of X and Z different prevents this rule from overlapping with rule #3 (which can result in any single solution being repeated more than once) and greatly reduces the number of inferences required to execute the query by avoiding unnecessary recursions.
Here is what you an do:
mysublist(L,L1):- sublist(L,L1), notnull(L).
notnull(X):-X\=[].
sublist( [], _ ).
sublist( [X|XS], [X|XSS] ) :- sublist( XS, XSS ).
sublist( [X|XS], [_|XSS] ) :- sublist( [X|XS], XSS ).
Taking a reference from this:
Prolog - first list is sublist of second list?
I just added the condition to check if it was empty beforehand.
Hope this helps.
If order matters. Example [1,2,3] is sublist of [1,2,3,4] but [1,3,2] not.
You can do something like this.
sublist([],L).
sublist([X|L1],[X|L2]):- sublist(L1,L2)
I would use append :
sublist(X, []) :-
is_list(X).
sublist(L, [X | Rest]) :-
append(_, [X|T], L),
sublist(T, Rest).
Basically we can check if M is a sublist of L if M exists in L by appending something on its back and/or its front.
append([], Y, Y).
append([X|XS],YS,[X|Res]) :- append(XS, YS, Res).
sublist(_, []).
sublist(L, M) :- append(R, _, L), append(_, M, R).

Resources