Counting within a list. Help me understand this code - prolog

I found a 3 year old question that helps me count the number of occurrences of variables within a list. The question had the answer below. The code works. But I can't understand how, can someone help me make sense of this?
Here is the answer with the code I found, writing in quotation marks is part of the answer:
count([],X,0).
count([X|T],X,Y):- count(T,X,Z), Y is 1+Z.
count([X1|T],X,Z):- X1\=X,count(T,X,Z).
'However note that the second argument X is supposed to be instantiated. So e.g. count([2,23,3,45,23,44,-20],23,C) will unify C with 2. If you want the count for every element use'
:- use_module(library(lists)).
count([],X,0).
count([X|T],X,Y):- count(T,X,Z), Y is 1+Z.
count([X1|T],X,Z):- X1\=X,count(T,X,Z)
countall(List,X,C) :-
sort(List,List1),
member(X,List1),
count(List,X,C).
'Then you get'
?- countall([2,23,3,45,23,44,-20],X,Y).
X = -20,
Y = 1 ;
X = 2,
Y = 1 ;
X = 3,
Y = 1 ;
X = 23,
Y = 2 ;
X = 44,
Y = 1 ;
X = 45,
Y = 1 ;
no
I am very new to Prolog, I only understand one part of this code, and it is this
sort(List,List1),
member(X,List1),
I would appreciate an explanation of this the whole thing, especially how Y is being printed.

About counting, first try to think about the meaning of the code.
list_member_occ([], _, 0). % list is empty, 0 occurrences
list_member_occ([X|Xs], X, N) :- % list has the element at the head
list_member_occ(Xs, X, N0), % count number of elements in the tail
succ(N0, N). % the number of occurrences is the
% next natural number
list_member_occ([Y|Xs], X, N) :-
dif(X, Y), % head and the element are different
list_member_occ(Xs, X, N). % occurrences in the tail of the list
% is the total number
In this code, succ(N0, N) is (arguably) a better way to say "N is the natural number after N0" than N is N0 + 1. One reason is that succ/2 was meant to be used in every direction:
?- succ(2, 3).
true.
?- succ(X, 4).
X = 3.
?- succ(1, X).
X = 2.
... while is/2 should be used with unbound left operand. Take this query
?- list_member_occ([1,1,2,1], X, 3).
... for an example of N being a number instead of a free variable.
Using the predicate:
?- list_member_occ([1,2,1], X, N).
X = 1,
N = 2 ;
X = 2,
N = 1 ;
N = 0,
dif(X, 1),
dif(X, 2),
dif(X, 1).
One interesting property of dif/2, as opposed to \=/2, is that it imposes a constraint on the variable X in the last solution: X cannot, from now on, take any of the values 1, or 2.
For the reason why you get all answers using dif/2, consider:
?- X = Y. % unify X and Y and succeed
X = Y.
?- X \= Y. % succeed if you cannot unify X and Y
false.
?- dif(X, Y). % succeed if X and Y are and will be different
dif(X, Y).
When you use X \= Y, Prolog tries to unify its arguments and fails if the unification succeeds. This means that you only get the solution in which all free variables have been unified to each other, but you miss solutions where free variables are different from each other.
About the Y = ..., when you make a query at the top level, it reports to you all new variable bindings that were made during successful proofs of this query. As the most simple example:
Which numbers are between 3 and 5, both including?
?- between(3, 5, X).
X = 3 ;
X = 4 ;
X = 5.
You don't need, of course, to print out the values of X by hand; just type a semicolon to get the next answer. After the last answer you get a full stop and return to the ?- prompt.
About the sorting: it sorts the whole list, but only shows you the first 9 elements of the sorted list. See this FAQ page from SWI-Prolog. In a nutshell, the easiest is to type ; true after your query, to make sure that there is at least one choice point, and use w and p to switch between showing the whole term and only some of it.
?- string_chars("the quick brown fox jumps over the lazy dog", Cs), sort(Cs, S) ; true.
Cs = [t, h, e, ' ', q, u, i, c, k|...],
S = [' ', a, b, c, d, e, f, g, h|...] [write]
Cs = [t, h, e, ' ', q, u, i, c, k, ' ', b, r, o, w, n, ' ', f, o, x, ' ', j, u, m, p, s, ' ', o, v, e, r, ' ', t, h, e, ' ', l, a, z, y, ' ', d, o, g],
S = [' ', a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z] .
?- string_chars("the quick brown fox jumps over the lazy dog", Cs), sort(Cs, S) ; true.
Cs = [t, h, e, ' ', q, u, i, c, k, ' ', b, r, o, w, n, ' ', f, o, x, ' ', j, u, m, p, s, ' ', o, v, e, r, ' ', t, h, e, ' ', l, a, z, y, ' ', d, o, g],
S = [' ', a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z] [print]
Cs = [t, h, e, ' ', q, u, i, c, k|...],
S = [' ', a, b, c, d, e, f, g, h|...] .
Hope this helps.

Related

Incorrect output when trying to query in a depth first search implementation for prolog

I just can't seem to get the correct output - I am supposed to get -
?- dfs([a], X).
X = [a, f, i] ;
false.
But I get -
?- dfs([a], X).
X = [a|f] ;
% Representation of a tree
% choose initial state a
arc(a, b).
arc(a, f).
arc(b, c).
arc(b, d).
arc(b, e).
arc(f, g).
arc(f, i).
arc(i, j).
arc(i, k).
% the goal
goal(i).
dfs([Node|_], [Node|X]) :-
goal(X).
dfs([Node|_], [Node|X]) :-
expands([Node|_], NewNode),
append([Node|_], NewNode, appendedN),
dfs(appendedN, X).
% expands(+Path, ?NewNode).
% -- Path: is a list of nodes of the form Path=[Node|Nodes], where
% Node is the node we want to expand and Nodes is a list
% of remaining nodes already expanded and containing the root.
% -- NewNode: is a constant representing the node we want to go to,
% as there is an link to it from where we are currently.
%
expands([Node|_], NewNode):-
arc(Node, NewNode).
Your program matches the first clause, dfs([Node|_], [Node|X]), and nothing else, producing X = [a|i] .
Here's a working version.
% Representation of a tree
% choose initial state a
arc(a, b).
arc(a, f).
arc(b, c).
arc(b, d).
arc(b, e).
arc(f, g).
arc(f, i).
arc(i, j).
arc(i, k).
% the goal
goal(i).
% You can expand a starting symbol S to a list L if G is your goal, S expands
% to G in list L1, and you append the two lists.
dfs([S], L) :-
goal(G),
expands(S, G, L1),
append([S], L1, L).
% X expands to Y in list [Y] if there's a direct arc from X to Y (base case).
expands(X, Y, [Y]) :-
arc(X, Y).
% X expands to Z in list [Y|L] if there's a direct arc from X to Y and Y
% expands to Z in list L (recursive case).
expands(X, Z, [Y|L]) :-
arc(X, Y),
expands(Y, Z, L).
In this version, expands() produces all of the lists that start with a:
?- expands(a, X, L).
X = b,
L = [b] ;
X = f,
L = [f] ;
X = c,
L = [b, c] ;
X = d,
L = [b, d] ;
X = e,
L = [b, e] ;
X = g,
L = [f, g] ;
X = i,
L = [f, i] ;
X = j,
L = [f, i, j] ;
X = k,
L = [f, i, k] ;
false.
Then dfs() confirms that the goal i has been reached and adds the start symbol a to the head of the list:
?- dfs([a], X).
X = [a, f, i] ;
false.

Prolog finding max of list with two values

So I am using prolog and i Have a funcntion like this:
ratingList(X):-goalKeeperRating(X,A),centreForwardRating(X,B),secondStrikerRating(X,C),centreDefenseRating(X,D),fullBackRating(X,E),centerMidfieldRating(X,F),attackingMidfieldRating(X,G),defendingMidfieldRating(X,H),
Y=[[goalKeeper,A],[centerForward,B],[secondStriker,C],[centerDefense,D],[fullBack,E],[centerMidfield,F],[attackingMidfieldRating,G],[defendingMidfieldRating,H]],
maxlist(Y,N),N=[L,M],write('Best Position ' + L + ' with rating ' +M).
Basically the first line finds numbers and put it in the second element, then we put numbers in a list (Y). Everything in Y is a list of length 2 with a soccer position name plus the number we got. MaxList just finds the maxinum number. it looks like this
maxlist([A],A).
maxlist([A,B|C],D):- A=[_,X],E=[_,Y],D=[_,Z],maxlist([B|C],E),max(X,Y,Z),.
max(A,B,A):-A>=B.
max(A,B,B):-A<B.
However, whenever I try to print the word it always results in printing the address. Is there anyway I can fix this?
You are constructing D without giving it's first element any value. The max function must work with the whole element not just the second element of the list. In your own style
maxlist([A], A).
maxlist([A, B | As], M) :-
maxlist([B | As], M1), max(A, M1, M).
max(A, B, A) :- A = [_, X], B = [_, Y], X >= Y.
max(A, B, B) :- A = [_, X], B = [_, Y], X < Y.
A iterative way to find the maximum of the list
maxlist([X | Xs], Max) :- maxlist(Xs, X, Max).
maxlist([], A, A).
maxlist([B | Bs], A, C) :-
A = [_, X], B = [_, Y],
(X > Y -> T = A ; T = B),
maxlist(Bs, T, C).

DAG Traversal + Cost in Prolog

I'm trying to implement a DAG traversal algorithm that also gets the costs between the edges. I think I'm pretty close but queries always return paths that aren't valid. Can anyone take a look and see what I'm missing here?
edge(b, a, 5).
edge(a, u, 10).
edge(u, o, 140).
edge(u, r, 130).
edge(r, o, 20).
edge(r, v, 50).
edge(o, v, 45).
edge(b, v, 20).
path(Start, Start, [], 0).
path(Start, Finish, [Start, Finish], C) :-
edge(Start, Finish, Cost),
C is Cost.
path(Start, Finish, [Start|Path], C) :-
edge(Start, X, Cost),
path(X, Finish, Path, RCost),
C is Cost + RCost.
I'm trying to run path(b, v, S, C).. It is generating all the valid paths, but it's also generating a few invalid paths.
C = 20,
S = [b, v]
C = 200,
S = [b, a, u, o, v]
C = 200,
S = [b, a, u, o]
C = 195,
S = [b, a, u, r, v]
C = 210,
S = [b, a, u, r, o, v]
C = 210,
S = [b, a, u, r, o]
C = 195,
S = [b, a, u, r]
C = 20,
S = [b]
Thanks.
The best graph traversal code I have seen is in this question:
Definition of a path/trail/walk
We can adapt that for your case to be:
edge(b, a, 5).
edge(a, u, 10).
edge(u, o, 140).
edge(u, r, 130).
edge(r, o, 20).
edge(r, v, 50).
edge(o, v, 45).
edge(b, v, 20).
:- meta_predicate path(3,?,?,?).
:- meta_predicate path(3,?,?,?,+).
path(R_3, [X0|Ys], X0,X) :-
path(R_3, Ys, X0,X, [X0]).
path(_R_3, [], X-0,X-0, _).
path(R_3, [X1-Cost2|Ys], X0-Cost,X, Xs) :-
call(R_3, X0,X1,Cost),
non_member(X1, Xs),
path(R_3, Ys, X1-Cost2,X, [X1-Cost2|Xs]).
non_member(_E, []).
non_member(E, [X-_Cost|Xs]) :-
dif(E,X),
non_member(E, Xs).
Then we can query :
?- path(edge,Path,From,To).
Path = [_22918-0],
From = To, To = _22918-0 ;
Path = [b-5, a-0],
From = b-5,
To = a-0 ;
Path = [b-5, a-10, u-0],
From = b-5,
To = u-0 ;
Path = [b-5, a-10, u-140, o-0],
From = b-5,
To = o-0 ;
Path = [b-5, a-10, u-140, o-45, v-0],
From = b-5,
To = v-0 ;
etc
So we get a list of nodes with the cost to get to the next node.
You can then simply sum them like this:
?- path(edge,Path,From,To), pairs_values(Path,Values), sumlist(Values,Sum).
Path = [_24478-0],
From = To, To = _24478-0,
Values = [0],
Sum = 0 ;
Path = [b-5, a-0],
From = b-5,
To = a-0,
Values = [5, 0],
Sum = 5 ;
Path = [b-5, a-10, u-0],
From = b-5,
To = u-0,
Values = [5, 10, 0],
Sum = 15 ;
Path = [b-5, a-10, u-140, o-0],
From = b-5,
To = o-0,
Values = [5, 10, 140, 0],
Sum = 155
etc
or you could adapt the code to count the sum as you go saving sum computation.
In this I think we are assuming that there is only one edge from any one node to another.
You have one error in your code. This:
path(Start, Start, [], 0).
should have been
path(Start, Start, [Start], 0).
otherwise Path in
path(Start, Finish, [Start|Path], C) :-
edge(Start, X, Cost),
path(X, Finish, Path, RCost),
C is Cost + RCost.
comes back empty from that (first) clause, but what you really intended here is for it to contain Finish as the last element.
Indeed this follows from the logical reading of your predicate as well. If path(Start, Start, Path, Cost) is to succeed, it means there's a Path from Start to Start, which is the non-empty [Start]. An empty path is no path at all.
Now all reported paths are valid. Some are reported multiple times, but that's another issue.

Fibonacci in Prolog - Breaks if False

I have a program fib(X,Y). If Y is the Xth Fibonacci number it returns True else it should return False. My program breaks anytime I input statement which is false.
fib(R,V) :- fib(0,1,R,V).
fib(X, Y, 0, V) :- Y == V.
fib(X, Y, R, V) :- Z is X + Y, C is R - 1, fib(Y, Z, C, V).
fib(0,1) -> True
fib(1,1) -> True
fib(2,2) -> True
fib(3,3) -> True
fib(4,5) -> True
fib(3,5) -> Won't finish.
What do I do wrong? I am using https://swish.swi-prolog.org/ to run my program queries.
The problem here is that you write two clauses fib(X, Y, 0, V) :- and fib(X, Y, R, V) :-. Prolog uses backtracking: in case one clause has been tried, it wil - regardless of sucess or failure - also later retry the next clause (there are some meta-predicates like once/1 that can alter this).
So even if R is 0, or lower, Prolog will also try the second clause.
A quick way to fix this is by using a guards for the second clause:
fib(_, Y, 0, V) :-
Y == V.
fib(X, Y, R, V) :-
R > 0,
Z is X + Y,
C is R - 1,
fib(Y, Z, C, V).
Furthermore your code is not very elegant in the sense that you can not use the relation in a reversed way, nor can we query for the X-th element.
For instance you use Y == V, but this blocks unification: if we want to know the X-th fibonacci number, we want a way to propagate the result back. So we can use unification instead:
fib(_, V, 0, V).
fib(X, Y, R, V) :-
R > 0,
Z is X + Y,
C is R - 1,
fib(Y, Z, C, V).
But now we still do not have a bidirectional relation: we can not obtain the X for a given value V. This is more complex. The easiest way is probably using clpfd for this:
:- use_module(library(clpfd)).
fib(_, V, 0, V).
fib(X, Y, R, V) :-
R #> 0,
V #>= Y,
Z is X + Y,
C #= R - 1,
fib(Y, Z, C, V).
Now we can:
enumerate all indices and the corresponding Fibonacci numbers:
?- fib(A,B).
A = 0,
B = 1 ;
A = B, B = 2 ;
A = B, B = 3 ;
A = 4,
B = 5 ;
A = 5,
B = 8 ;
A = 6,
B = 13 ;
A = 7,
B = 21
...
Obtain the i-th Fibonacci number:
?- fib(2,B).
B = 2 ;
false.
?- fib(10,B).
B = 89 ;
false.
obtain the i for which the corresponding Fibonacci number is a certain value:
?- fib(A,1).
A = 0 ;
A = 1 ;
false.
?- fib(A,2).
A = 2 ;
false.
?- fib(A,3).
A = 3 ;
false.
?- fib(A,4).
false.
?- fib(A,5).
A = 4 ;
false.
Check if the i-th Fibonacci number is a given value:
?- fib(4,5).
true ;
false.
?- fib(4,6).
false.
?- fib(4,10).
false.
?- fib(5,8).
true ;
false.

How to get the value of many elements of a matrix (list of lists)

I have problems because I want to get the values of many grids of a matrix
Example:
I have this matrix (list of lists)
[[g,z,n,d,o,g,r,o,y,c],
[a,u,u,d,p,o,x,s,t,b],
[u,y,z,r,r,e,m,e,e,o],
[g,v,j,m,x,e,j,e,h,l],
[e,r,u,y,d,z,k,b,r,x],
[e,d,h,n,c,y,q,e,x,i],
[w,f,m,w,x,n,n,m,h,i],
[y,d,g,u,q,d,z,o,n,d],
[g,p,o,u,c,o,n,f,x,q],
[c,y,z,r,i,c,a,t,x,v]]
I want to get the word "dog" from this matrix, this word is in the coordinates (0 3) (0 4) (0 5).
Now the problem is how I can do this in prolog?
My code so far:
selectElementList(0,[H|_],H).
selectElementList(P,[H|T],E):-
length([H|T],Len),
( P < Len
-> P1 is P - 1,
selectElementList(P1,T,E),
!
; E = false,
!
).
With this predicate I get one value of the matrix.
selectGridMatrix(Matrix,X,Y,R):-
selectElementList(X,Matrix,Row), selectElementList(Y,Row,R).
Example:
?- selectGridMatrix([[0,1,2],[3,4,5]],0,0,R).
R = 0 ;
an example, using builtin nth0/3 and library(yall):
?- M= [[g,z,n,d,o,g,r,o,y,c],
[a,u,u,d,p,o,x,s,t,b],
[u,y,z,r,r,e,m,e,e,o],
[g,v,j,m,x,e,j,e,h,l],
[e,r,u,y,d,z,k,b,r,x],
[e,d,h,n,c,y,q,e,x,i],
[w,f,m,w,x,n,n,m,h,i],
[y,d,g,u,q,d,z,o,n,d],
[g,p,o,u,c,o,n,f,x,q],
[c,y,z,r,i,c,a,t,x,v]], maplist({M}/[(R,C),V]>>(nth0(R,M,Row),nth0(C,Row,V)),[(0,3),(0,4),(0,5)],Word).
M = [[g, z, n, d, o, g, r, o|...], [a, u, u, d, p, o, x|...], [u, y, z, r, r, e|...], [g, v, j, m, x|...], [e, r, u, y|...], [e, d, h|...], [w, f|...], [y|...], [...|...]|...],
Word = [d, o, g].
HTH

Resources