gprolog difference list with duplicate - prolog

i have to get list difference between two integer list (both ordinate).
i white this:
difference(L,[],L) :- !.
difference([],_,[]) :- !.
difference([],[],W).
difference([H|T1],[D|T2],T3) :- difference(T1,[D|T2],[H|T3]).
difference([H|T1],[H|T2],T3) :- difference(T1,T2,T3).
but why i can't get my list difference?
if i write this:
difference([],[],W):- write(X).
and this example:
| ?- difference([1,4,4],[1,4],R).
[4|_27]
it makes right!
NB if i have duplicate number i have to show it!

I find your code rather odd. For instance, your third clause: what's W for? Seems like you mean to say:
difference([],[],_).
Second problem: in the fourth clause, there's nothing stopping H and D from being independent variables with the same binding. I suspect you mean something like this:
difference([H|T1],[D|T2],T3) :- H \= D, difference(T1,[D|T2],[H|T3]).
Fixing these things seems to fix the predicate to give a reasonable looking answer:
| ?- difference([1,4,4], [1,4], R).
R = [4]
I think your first several clauses are trying to handle different sorts of base cases, is that right? E.g.:
difference(L, [], L) % handles the case where the second list is exhausted
difference([], _, []) % handles the case where the first list is exhausted
difference([], [], W) % handles the case where the lists are exhausted at the same time
One problem with this is that L = [] is a legitimate binding, so the first and third clauses mean the same thing. You can probably safely remove the third one, because it would have matched and produced the same answer on the first. The second clause is more interesting, because it seems to say that regardless of whatever work we've done so far, if the first list is empty, the result is empty. I find that possibility a bit jarring--is it possible you actually want these two base cases? :
difference([], L, L).
difference(L, [], L).
I remain unconvinced, but until I have a better idea what you're trying to accomplish I may not be able to help more. For instance, what should happen with difference([1, 4], [1, 4, 4], R)? I posit you probably want R = [4], but your code will produce R = [].
Also, I find it unlikely that
difference([],[],W):- write(X).
is going to be a helpful debugging strategy, because Prolog will generate a new variable binding for X because there's nothing for it to refer to.
The final version I have with all my changes looks like this:
difference(L, [], L) :- !.
difference([], L, L) :- !.
difference([H|T1], [D|T2], T3) :- D \= H, difference(T1, [D|T2], [H|T3]).
difference([H|T1], [H|T2], T3) :- difference(T1, T2, T3).
Edit: does this implement your requirements?
not_in1(X, Left, Right) :- member(X, Left), \+ member(X, Right).
not_in(X, Left, Right) :- not_in1(X, Left, Right).
not_in(X, Left, Right) :- not_in1(X, Right, Left).
differences(Left, Right, Differences) :-
findall(X, not_in(X, Left, Right), Differences).
?- differences([1,2,3,4], [1,3,5], X).
X = [2,4,5]
If so, I'll try to get your original code to produce answers that match.
Edit 2: OK, so the problem with the solution above is that it is O(N^2). In the worst case (two totally distinct lists) it will have to compare every item from list 1 to every item of list 2. It's not exploiting the fact that both lists are ordered (I believe that's what you mean by 'ordinate').
The result looks a lot more like your original code, but your original code is not taking advantage of the fact that the items are ordered. This is why the fourth and fifth cases are confusing looking: you should recur down one of the lists or the other depending on which number is larger. The corrected code looks like this:
differences([], Result, Result).
differences(Result, [], Result).
differences([H|Ls], [H|Rs], Result) :- differences(Ls, Rs, Result).
differences([L|Ls], [R|Rs], [L|Result]) :-
L < R,
differences(Ls, [R|Rs], Result).
differences([L|Ls], [R|Rs], [R|Result]) :-
L > R,
differences([L|Ls], Rs, Result).
You can see this produces the same result as the O(N^2) method:
?- differences([1,2,3,4], [1,3,5], X).
X = [2,4,5]
You were right, you do need both base cases. This is so the remainder of either list becomes part of the result. Presumably these will be the largest values ([5] in the example).
Now I have three inductive cases: one for <, one for > and one for =. The equality case is intuitive: recur on both lists, discarding the head of both lists. The next case basically says if the left head is less than the right head, add it to the result and recur on the left's tail. The right is unchanged in that case. The other case is the mirror of this case.
Hope this helps!

Related

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.

How to improve this code that looks for a specific number in a list?

I'm writing prolog code that finds a certain number; a number is the right number if it's between 0 and 9 and not present in a given list. To do this I wrote a predicate number/3 that has the possible numbers as the first argument, the list in which the Rightnumber cannot be present and the mystery RightNumber as third argument:
number([XH|XT], [H|T], RightNumber):-
member(XH, [H|T]), !,
number(XT, [H|T], RightNumber).
number([XH|_], [H|T], XH):-
\+ member(XH, [H|T]).
so this code basically says that if the Head of the possible numbers list is already a member of the second list, to cut of the head and continue in recursion with the tail.
If the element is not present in the second list, the second clause triggers and tells prolog that that number is the RightNumber. It's okay that it only gives the first number that is possible, that's how I want to use it.
This code works in theory, but I was wondering if there's a better way to write it down? I'm using this predicate in another predicate later on in my code and it doesn't work as part of that. I think it's only reading the first clause, not the second and fails as a result.
Does anybody have an idea that might improve my code?
sample queries:
?- number([0,1,2,3,4,5,6,7,8,9], [1,2], X).
X = 3
?- number([0,1,2,3,4,5,6,7,8,9], [1,2,3,4,5,6,7,8,0], X).
X = 9
First, the code does not work. Consider:
?- number(Xs, Ys, N).
nontermination
This is obviously bad: For this so-called most general query, we expect to obtain answers, but Prolog does not give us any answer with this program!
So, I first suggest you eliminate all impurities from your program, and focus on a clean declarative description of what you want.
I give you a start:
good_number(N, Ls) :-
N in 0..9,
maplist(#\=(N), Ls).
This states that the relation is true if N is between 0 and 9, and N is different from any integer in Ls. See clpfd for more information about CLP(FD) constraints.
Importantly, this works in all directions. For example:
?- good_number(4, [1,2,3]).
true.
?- good_number(11, [1,2,3]).
false.
?- good_number(N, [1,2,3]).
N in 0\/4..9.
And also in the most general case:
?- good_number(N, Ls).
Ls = [],
N in 0..9 ;
Ls = [_2540],
N in 0..9,
N#\=_2540 ;
Ls = [_2750, _2756],
N in 0..9,
N#\=_2756,
N#\=_2750 .
This, with only two lines of code, we have implemented a very general relation.
Also see logical-purity for more information.
First of all, your predicate does not work, nor does it check all the required constraints (between 0 and 9 for instance).
Several things:
you unpack the second list [H|T], but you re-pack it when you call member(XH, [H|T]); instead you can use a list L (this however slightly alters the semantics of the predicate, but is more accurate towards the description);
you check twice member/2ship;
you do not check whether the value is a number between 0 and 9 (and an integer anyway).
A better approach is to construct a simple clause:
number(Ns, L, Number) :-
member(Number, Ns),
integer(Number),
0 =< Number,
Number =< 9,
\+ member(Number, L).
A problem that remains is that Number can be a variable. In that case integer(Number) will fail. In logic we would however expect that Prolog unifies it with a number. We can achieve this by using the between/3 predicate:
number(Ns, L, Number) :-
member(Number, Ns),
between(0, 9, Number),
\+ member(Number, L).
We can also use the Constraint Logic Programming over Finite Domains library and use the in/2 predicate:
:- use_module(library(clpfd)).
number(Ns, L, Number) :-
member(Number, Ns),
Number in 0..9,
\+ member(Number, L).
There are still other things that can go wrong. For instance we check non-membership with \+ member(Number, L). but in case L is not grounded, this will fail, instead of suggesting lists where none of the elements is equal to Number, we can use the meta-predicate maplist to construct lists and then call a predicate over every element. The predicate we want to call over every element is that that element is not equal to Number, so we can use:
:- use_module(library(clpfd)).
number(Ns, L, Number) :-
member(Number, Ns),
Number in 0..9,
maplist(#\=(Number), L).

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.

What's happening when reversing a list with append in Prolog?

I don't quite understand whats happening the this code:
reverse2([],[]).
reverse2([H|T],R):- reverse2(T,R2), append(R2,[H],R).
It doesn't make sense to me that we are recursing before appending.
Could someone explain it how each element H is being appending after the base case is reached?
Thanks.
The recursion is on the tail of the list. Consider the list [1,2,3]. The first rule doesn't match. The second rule matches, unifying H = 1 and T = [2,3]. Then we call reverse2([2,3], R2). Again, the first rule doesn't match. The second rule matches, unifying H = 2 and T = [3]. You can see that recursion from here will eventually hit the first rule. Zooming back to the outermost call where H = 1 and T = [2, 3], we will wind up with R2 = [3, 2]. Then the append will occur, sticking [1] on the end.
You may find it instructive to do a sample query like this:
?- trace, reverse2([1,2,3], X).
This will show you how the query unfolds and the bindings of each variable.
The way to think about recursive functions is inductively. Look at the base case. The base case should be trivially true, and it is--the reverse of the empty list is indeed the empty list. Then look at the inductive case. Assuming that it works for a smaller list of size N, does it work for a list of size N+1? Assume it can reverse the tail of the list (size = N), and see that if that is true, appending the head to the end would make it work for N+1. That's all you need to believe for induction to work. If you believe those two things, you believe everything there is to believe and it will work for every input. So liberate yourself from the need to believe in any other steps. :)
Just to build a little on Daniel's description, you could read the recursive clause:
reverse2([H|T], R) :- reverse2(T, R2), append(R2, [H], R).
As:
R is the reverse of list [H|T] if R2 is the reverse of T, and R is the list [H] appended to the end of list R2.
Or, somewhat imperatively, as:
To reverse a list, first reverse its tail, then append the head of the original list to that result.
So in that description, the recursive goal of reverse2(T, R2) comes first.
The definition in this case is depth first. It's going to keep recursing until it hits the trivial base case, then return from each goal doing the appends:
(1) reverse2([1,2,3], R) :- reverse2([2,3], R2), append(R2, [1], R).
(2) reverse2([2,3], R) :- reverse2([3], R2), append(R2, [2], R).
(3) reverse2([3], R) :- reverse2([], R2), append(R2, [3], R).
(4) reverse2([], []).
Then the returns:
(3) reverse2([3], R) :- reverse2([], []), append([], [3], R). % R = [3]
(2) reverse2([2,3], R) :- reverse2([3], [3]), append([3], [2], R). % R = [3,2]
(1) reverse2([1,2,3], R) :- reverse2([2,3], [3,2]), append([3,2], [1], R).
Result:
reverse2([1,2,3], [3,2,1]).
As an aside, this is actually a fairly inefficient way to do a reverse/2 predicate. And it has some issues if you do, reverse(L, [1,2,3]) after it finds the first solution. It's interesting to note that if you swap the recursion and the append/3 queries around:
reverse2([H|T], R) :- append(R2, [H], R), reverse2(T, R2).
This actually behaves better on reverse2(L, [1,2,3]) but then has a problem after finding the first solution to reverse2([1,2,3], L). The opposite of what happens with the case in which the recursive query comes first. With this definition, if the first argument is bound but not the second, it has the inefficiency of finding irrelevant possible solutions to the append(R2, [H], R) first when neither R2 or R are initially bound before it finds the correct solution through the subsequent recursion. Then after finding that solution, it infinitely tries more irrelevant potential solutions emerging from backtracks to append/3.
If you look up the source code for reverse/2 in the SWI Prolog implementation, it uses pure recursion and difference lists to overcome these shortcomings.

Poker Hand in Prolog

I am trying to write a predicate to analyse common poker hands; for example given a list of "cards" identify if the player has 4 of a kind; 3 of a kind; pair etc:
My idea was to check for similar rank and remove if not:
this works for fourofakind(["A","J",10,"Q","A","A","A"])
but not all scenarios; any guidance on the logic here?
Thanks
The problem is that you only check whether the first card in the hand appears four times in the set. You will need to do that for all cards.
I would introduce an auxiliary predicate that counts the number of cards you have seen, and let the main predicate iterate over the cards in the hand until you've found a set of four:
four([H|T]) :- four0(H,1,T), !. % find a set of four Hs
four([_|T]) :- four(T). % else continue with remaining set
four0(_,4,_) :- !. % found four cards: stop
four0(X,I,[X|T]) :- !,I1 is I+1,four0(X,I1,T). % found another card: inc counter
four0(X,I,[_|T]) :- four0(X,I,T). % else continue
If it wasn't for short lists you could improve it by, e.g., remembering what cards you already checked or removing them. It also would be much easier if the list was sorted to begin with.
BTW, you can simplify the nested list in your original first clause as [H,H,H,H], and in the second clause as [H1,H2|T]. It's easier on the eyes!
Consider to put to good use the builtins: when you sort a list all elements get grouped, then check for a sequence become easy:
fourofakind(Hand) :- % not intersted to what card is
fourofakind(Hand, _).
fourofakind(Hand, C) :-
msort(Hand, Sorted),
append([_, [C,C,C,C], _], Sorted).
The predicate has 2 forms, the latter also provides the card code. Please use the msort call: using sort we lose duplicates...
As chac pointed out and to have again the debate we had in this post, you can use append to successfully parse your list once sorted quite easily. Without sorting, you could write :
fourofakind(Hand, X) :- append([_, [X], _, [X], _, [X], _, [X], _], Hand).
This basically tells prolog : I want my hand to have 4 times the sublist [X] with anything in-between.
Or, to use what #false describes as a very graphically appealing solution in his reply on the other thread (DCGs) :
four --> ..., [X], ..., [X], ..., [X], ..., [X], ... .
... --> [] | [_], ... .
?- Xs = "bacada", phrase(four, Xs).
You could too avoid using too many built-ins by doing the work with basic recursion :
three_of_a_kind(Item, [Item|Tail]) :- pair(Item, Tail).
three_of_a_kind(Item, [_Item|Tail]) :- three_of_a_kind(Item, Tail).
pair(Item, [Item|Tail]) :- one(Item, Tail).
pair(Item, [_NotItem|Tail]) :- pair(Item, Tail).
one(Item, [Item|_Tail]).
one(Item, [_NotItem|Tail]) :- one(Item, Tail).
Note that here one/2 is equivalent to the naive definition of member/2. I let you the task of adding four_of_a_kind/1 by looking at how three_of_a_kind/1 and pair/2 work ! Use of cut would be interesting too to remove unused choice points.

Resources