Swi Prolog - Implementing water Jug Program with Lists - list

sorry about before, new to posting in this, trying to get this list to recurse through each one of the actions, keeping it's visited list items and then check in a recursion if the element is not in the list that state would be changed to. I need to find out why this is not working as expected, it seems to get results 7,0, 0,0, 0,4 and 7,4 and the check seems to show the same 4 outcomes in the one run of this program, randomly spitting one of those out, is the action order wrong as I know you have to go from hardest condition to match, the goal is to fill this using call solve(state(0,0)). Then you should get 5 in the jug in the end call, and print out the list that shows the path it used and then find another solution, as there can only be two where there is 5L in the 7L jug.
action(state(L,R), P, state(7,R)) :-
L < 4,
not(lists:member(state(7,R),P)),
print(state(7,R)).
action(state(L,R), P, state(L,4)) :-
R < 4,
not(lists:member(state(L,4),P)),
print(state(L,4)).
action(state(L,R), P, state(0,R)) :-
L > 0,
not(lists:member(state(0,R),P)),
print(state(0,R)).
action(state(L,R), P, state(L,0)) :-
R > 0,
not(lists:member(state(L,0),P)),
print(state(L,0)).
action(state(L,R), P, state(7,C)) :-
not(lists:member(state(7,C),P)),
C is L + R -7,
C > 7,
print(state(7,C)).
action(state(L,R), P, state(C,4)) :-
not(lists:member(state(C,4),P)),
C is L + R -4,
C > 4,
print(state(C,4)).
action(state(L,R), P, state(0,C)) :-
not(lists:member(state(0,C),P)),
C is L + R,
C #=< 4,
print(state(0,C)).
action(state(L,R), P, state(C,0)) :-
not(lists:member(state(C,0),P)),
C is L + R,
C #=< 7,
print(state(C,0)).
solve(X) :-
reachedgoal(X,[],A).
reachedgoal(state(5,_),L,L).
reachedgoal(State1,P,L) :-
action(State1,P,State2),
not(lists:member(State2,P)),
reachedgoal(State2,[State1|P],L).

There were some little logical mistakes, and it does not make sense to check for duplicate action before you have calculated the values.
solve(X) :-
reachedgoal(X,[],_).
reachedgoal(state(5,_),L,L).
reachedgoal(State1,P,L) :-
action(State1,P,State2),
\+ member(State2,P),
reachedgoal(State2,[State1|P],L).
action(state(_L,R),P,state(7,R)) :- % fill left jug (7l)
\+ member(state(7,R),P),
print(state(7,R)),nl.
action(state(L,_R),P,state(L,4)) :- % fill right jug (4l)
\+ member(state(L,4),P),
print(state(L,4)),nl.
action(state(_L,R),P,state(0,R)) :- % empty left jug
\+ member(state(0,R),P),
print(state(0,R)),nl.
action(state(L,_R),P,state(L,0)) :- % empty right jug
\+ member(state(L,0),P),
print(state(L,0)),nl.
action(state(L,R),P,state(7,C)) :- % from right jug to left jug until left full
C is L + R - 7,
C > 0, C =< 4,
\+ member(state(7,C),P),
print(state(7,C)),nl.
action(state(L,R),P,state(C,4)) :- % from left jug to right jug until right full
C is L + R - 4,
C > 0, C =< 7,
\+ member(state(C,4),P),
print(state(C,4)),nl.
action(state(L,R),P,state(0,C)) :- % from left jug to right jug until left empty
C is L + R,
C =< 4,
\+ member(state(0,C),P),
print(state(0,C)),nl.
action(state(L,R),P,state(C,0)) :- % from right jug to left jug until right empty
C is L + R,
C =< 7,
\+ member(state(C,0),P),
print(state(C,0)),nl.
This produces:
| ?- solve(state(0,0)).
state(7,0)
state(7,0)
state(7,4)
state(7,4)
state(0,4)
state(0,4)
state(4,0)
state(4,4)
state(4,4)
state(7,1)
state(7,1)
state(0,1)
state(0,1)
state(1,0)
state(1,4)
state(1,4)
state(5,0)
yes
The duplications are because of insufficient conditions in the actions (see below).
Checking for duplicate state in each of the actions in wasteful, as you are also checking it in reachedgoal/3, and it is nicer and cleaner to just print the list at the end.
solve :-
solve(state(0,0),RevStates), reverse(RevStates,States),
write(States), nl.
solve(X,States) :-
reachedgoal(X,[],States).
reachedgoal(state(5,_),L,L).
reachedgoal(State1,P,L) :-
action(State1,State2),
\+ member(State2,P),
reachedgoal(State2,[State1|P],L).
action(state(L,R),state(7,R)) :- % fill left jug (7l)
L < 7.
action(state(L,R),state(L,4)) :- % fill right jug (4l)
R < 4.
action(state(L,R),state(0,R)) :- % empty left jug
L > 0.
action(state(L,R),state(L,0)) :- % empty right jug
R > 0.
action(state(L,R),state(7,C)) :- % from right jug to left jug until left full
R > 0, L < 7,
C is L + R - 7, C > 0, C =< 4.
action(state(L,R),state(C,4)) :- % from left jug to right jug until right full
L > 0, R < 4,
C is L + R - 4, C > 0, C =< 7.
action(state(L,R),state(0,C)) :- % from left jug to right jug until left empty
L > 0, C is L + R, C =< 4.
action(state(L,R),state(C,0)) :- % from right jug to left jug until right empty
R > 0, C is L + R, C =< 7.
Now there are no duplicates:
| ?- solve.
[state(0,0),state(7,0),state(7,4),state(0,4),state(4,0),state(4,4),state(7,1),state(0,1),state(1,0),state(1,4)]
yes

Related

Calculating List of positive numbers of a given list in Prolog

I tried resolving it by myself in the following way:
list_of_positives(L1, L2) :-
list_of_positives(L1, L2, []).
list_of_positives([], L, L).
list_of_positives([H|T], L2, L3) :-
( H > 0
-> list_of_positives(T,L2,[H|L3])
; list_of_positives(T,L2,L3)
).
The problem with this solution is that I get as response a reversed list of positive numbers. Can someone help me to find a way to get the list in the "correct order"?
You can solve the problem as follows:
positives([], []).
positives([H|T], P) :-
( H > 0
-> P = [H|R] % desired order!
; P = R),
positives(T, R) .
Example:
?- positives([2,-3,6,-7,1,4,-9], P).
P = [2, 6, 1, 4].
You want to use a difference list, a non-closed, or open list. So, something like this:
positives( [] , [] ) . % An empty list has not positives, and closes the list.
positives( [N|Ns] , [N|Rs] ) :- % For a non-empty list, we prepend N to the result list
N > 0, % - if N is positive
positives(Ns,Rs) % - and recurse down.
. %
positives( [N|Ns] , Rs ) :- % For non-empty lists, we discard N
N =< 0, % - if N is non-positive
positives(Ns,Rs) % - and recurse down.
. %

Count numbers in list

I have a problem with calculating the occurences of the given number in list. For instance, if we have a list like L = [4,5,6,4,3,4,2,4,5,6,7,4] and I want to count how many 4s is in the list, then the answer is 5.
I tried to implement this in prolog, but gprolog shows me only no as an answer:
count_occ([], 0).
count_occ([H|T], L) :- count_occ(T, N), H =:= 4, L is N + 1.
And I do not know why.
I took a stab at this. I made it extra verbose so it's easy to follow along:
% count_occurences(+List, +DesiredElement, -NumOccurences)
count_occurences([], _, 0).
count_occurences([H|T], DesiredElement, NumOccurences) :-
H =\= DesiredElement,
count_occurences(T, DesiredElement, NumOccurences).
count_occurences([H|T], DesiredElement, NumOccurences) :-
H =:= DesiredElement,
count_occurences(T, DesiredElement, N),
NumOccurences is N + 1.
Using a conditional expression, the last 2 predicates can be combined into one:
% count_occurences(+List, +DesiredElement, -NumOccurences)
count_occurences([], _, 0).
count_occurences([H|T], DesiredElement, NumOccurences) :-
count_occurences(T, DesiredElement, N),
(H =:= DesiredElement -> /* if H is DesiredElement */
NumOccurences is N + 1; /* "then" */
NumOccurences is N /* "else" */
).
I think the problem is that you do not provide a clause Prolog can take when H is not 4. This one is however easy: you simply perform a recursive call:
count_occ([H|T],N) :-
H \= 4,
count_occ(T,N).
Or a full implementation:
count_occ([],0).
count_occ([4|T],N1) :-
count_occ(T,N),
N1 is N+1.
count_occ([H|T],N) :-
H \= 4,
count_occ(T,N).

How to find the Nth element of a list in Prolog

I am trying to write a Prolog code finding the n-th element of a list.
I wrote the below code but it doesn't return the element right.
match([Elem|Tail],Num,Num,Elem).
match([Elem|Tail],Num,C,MatchedNumber):-
match(Tail,Num,N,Elem),
C is N+1.
In the first line I say, if the requested element number is equal to counter, then give the first element of the current list to the variable called MatchedNumber. This code returns the Num and Counter right but I don't know why when I want to set the MatchedNumber as Elem, it always returns the first element of the list.
1: what is wrong with this code?
2: How can I say instead of showing the matched number, remove it from list?
First of all, there is a builtin nth0/3 for that:
?- nth0(0,[a,b,c],X).
X = a.
?- nth0(1,[a,b,c],X).
X = b.
?- nth0(2,[a,b,c],X).
X = c.
?- nth0(3,[a,b,c],X).
false.
Get the i-th element
The problem is in the inductive case:
match([Elem|Tail],Num,Counter,MatchedNumber):-
match(Tail,Num,N,Elem),
C is N+1.
Prolog doesn't know anything about C so the last statement doens't force Prolog to return the i-th element. It can simply return any element because N will match with Num in the recursive call and then set C to Num+1 but that's not a problem because C is not bound by anything.
A better way to solve this, is using a decrement counter:
match([H|_],0,H) :-
!.
match([_|T],N,H) :-
N > 0, %add for loop prevention
N1 is N-1,
match(T,N1,H).
Example:
?- match([a,b,c,d,e],0,X).
X = a.
?- match([a,b,c,d,e],1,X).
X = b.
?- match([a,b,c,d,e],2,X).
X = c.
?- match([a,b,c,d,e],3,X).
X = d.
?- match([a,b,c,d,e],4,X).
X = e.
?- match([a,b,c,d,e],5,X).
false.
The base case is thus that the index is 0 in which case you return the head, otherwise you query for the i-1-th element of the tail. This is also a more declarative approach.
This approach also makes use of tail recursion which in general will boost performance significantly.
Modifying the original predicate
It is rather un-Prolog to use an iterator and a bound, one in general uses a reverse iterator.
You can however modify the predicate as follows:
match([Elem|_],Num,Num,Elem) :-
!.
match([_|Tail],Num,Count,MatchedNumber) :-
Count < Num,
Count1 is Count+1,
match(Tail,Num,Count1,MatchedNumber).
So a few errors:
Use a "cut" ! in the first clause: since if it matches, we know Prolog should not try the second one;
Use MatchedNumber in the recursive call instead of Elem;
Perform a bound check Count < Num,
Do the increment of the counter Count1 is Count+1 before doing the recursive call; and
Substitute all variables you do not use by underscores _.
An example is then:
?- match([a,b,c,d,e],0,0,X).
X = a.
?- match([a,b,c,d,e],1,0,X).
X = b.
?- match([a,b,c,d,e],2,0,X).
X = c.
?- match([a,b,c,d,e],3,0,X).
X = d.
?- match([a,b,c,d,e],4,0,X).
X = e.
?- match([a,b,c,d,e],5,0,X).
false.
But as said before, it is inefficient to pass an additional argument, etc.
Remove the i-th element from the list
An almost equivalent approach can be used to remove the i-th element from the list:
removei([],_,[]).
removei([_|T],0,T) :-
!.
removei([H|T],N,[H|TR]) :-
N1 is N-1,
removei(T,N1,TR).
Here the base case is again that the index is 0 in which case the tail of the list is removed (thus dropping the head). The inductive case will place the head of the list in the head of the resulting list and will count on the recursive call to remove the correct item from the tail. Another base case removei([],_,[]). is added because it is possible that i is greater than the length of the list in which case this predicate won't remove any item.
Example
?- removei([a,b,c,d,e],0,X).
X = [b, c, d, e].
?- removei([a,b,c,d,e],1,X).
X = [a, c, d, e].
?- removei([a,b,c,d,e],2,X).
X = [a, b, d, e].
?- removei([a,b,c,d,e],3,X).
X = [a, b, c, e].
?- removei([a,b,c,d,e],4,X).
X = [a, b, c, d].
?- removei([a,b,c,d,e],5,X).
X = [a, b, c, d, e].
?- removei([a,b,c,d,e],6,X).
X = [a, b, c, d, e].
To find the nth element of a list (where n is relative to zero), something like this ought to suffice:
find_nth_element_of_list( 0 , X , [X|_] ) .
find_nth_element_of_list( N , X , [_|Xs] ) :-
N > 0 ,
N1 is N-1 ,
find_nth_element_of_list( N1 , X , Xs )
.
Similarly, to remove the nth element of a list, something like this ought to suffice:
remove_nth_element_of_list( 0 , [_|Xs] , Xs ) . % at n=0, toss the head and unify the tail with the result set
remove_nth_element_of_list( N , [X|Xs] , [X|Ys] ) :- % at n>0, prepend the head to the result and recurse down.
N > 0 ,
N1 is N-1 ,
remove_nth_element_of_list( N1 , Xs , Ys )
.
If for some reason you need to achieve this using no built-in predicates besides append here is my implementation:
my_length([], 0).
my_length([_|T], N1) :- my_length(T, N), N1 is N + 1.
% Nth
my_nth(N, List, H) :-
append(L1, [H|_], List),
my_length(L1, N),
!.
test_my_nth(X, Y, Z) :-
my_nth(0, [123, 456, 789], X),
my_nth(1, [123, 456, 789], Y),
my_nth(2, [123, 456, 789], Z).
% X = 123
% Y = 456
% Z = 789
and without append:
my_length([], 0).
my_length([_|T], N1) :- my_length(T, N), N1 is N + 1.
% Nth
my_nth(0, [H|_], H) :- !.
my_nth(N, [_|T], Result) :-
N1 is N - 1,
my_nth(N1, T, Result),
!.
test_my_nth(X, Y, Z) :-
my_nth(0, [123, 456, 789], X),
my_nth(1, [123, 456, 789], Y),
my_nth(2, [123, 456, 789], Z).
% X = 123
% Y = 456
% Z = 789
And without !:
my_length([], 0).
my_length([_|T], N1) :- my_length(T, N), N1 is N + 1.
% Nth
my_nth(N, [_|T], Result) :-
N > 0,
N1 is N - 1,
my_nth(N1, T, Result).
my_nth(0, [H|_], H).
test_my_nth(X, Y, Z) :-
my_nth(0, [123, 456, 789], X),
my_nth(1, [123, 456, 789], Y),
my_nth(2, [123, 456, 789], Z).
% X = 123
% Y = 456
% Z = 789
Why would anyone need it? There is a specific professor at Poznan University of Technology that requires students to write predicates like this.

List of factorials in Prolog

I'm having trouble solving the following exercise...
A factorial can be described in Prolog as:
factorial(0, 1).
factorial(N, F) :-
N1 is N - 1,
factorial(N1, F1),
F is N * F1.
I need to expand this code in order to return a list of all previous factorials until N. But it returns only the first factorial (1), and then the error: ERROR: Out of local stack. Here is my code:
insertList(H, L, [H|L]) :-
!.
factorial(0, 1, [1]).
factorial(N, F, L) :-
N1 is N - 1,
factorial(N1, F1, L),
F is N * F1,
insertList(F, L, [F|L]).
list_factorial(X, L) :-
factorial(X, F, L).
What am I doing wrong?
Here's an implementation in pure prolog with clpfd:
:- use_module(library(clpfd)).
list_factorial([1], 0).
list_factorial(Zs0, N) :-
length(Zs0, N),
N #> 0,
list_n_fac(Zs0, 1, 1).
list_n_fac([], _, _).
list_n_fac([Z1|Zs], N0, Z0) :-
Z1 #= Z0 * N0,
N1 #= N0 + 1,
list_n_fac(Zs, N1, Z1).
Sample query:
?- list_factorial(Zs, 8).
Zs = [1,2,6,24,120,720,5040,40320].
Here's the most general query:
?- list_factorial(Zs, N).
( N = 0, Zs = [1]
; N = 1, Zs = [1]
; N = 2, Zs = [1,2]
; N = 3, Zs = [1,2,6]
; N = 4, Zs = [1,2,6,24]
; N = 5, Zs = [1,2,6,24,120]
...
the minimal correction, indicating the main problem
insertList(H, L, [H|L]):- !.
factorial(0, 1, [1]).
factorial(N, F, Fs):- N1 is N-1, factorial(N1, F1, L), F is N * F1, insertList(F, L, Fs).
list_factorial(X, L):- factorial(X, F, L).
but it will loop if you request backtracking after the first solution is returned. You could add the test #false suggested... otherwise, another definition could be
factorials(N, L) :-
N > 0 -> L = [F,G|Fs], M is N-1, factorials(M, [G|Fs]), F is G*N ; L = [1].
Another solution is:
factorial(0,1) :- !.
factorial(N,F) :-
N>0, N1 is N - 1, factorial(N1,F1), F is N * F1.
list_factorial(N,L) :-
N>1, !, N2 is N-1, list_factorial(N2,L2), factorial(N,F), append(L2,[F],L).
list_factorial(N,[F]) :- factorial(N,F).
I changed your factorial with the test if N is greater than 0, because you can't do the factorial of negative number and with a cut to get only one solution.
You made me install SWI-prolog haha.
list_fact(N,M,A):- A is N * M.
list_fact(N,M,A):- N1 is N + 1, M1 is N * M, list_fact(N1,M1,A).
Call as
list_fact(1,1,A).
It's quite simple. The first rule calculates the next factorial as N * M.
The second rule makes a recursive call where N = N + 1 and M = the previous factorial calculated in rule 1.

Prolog - Replacing X number of elements of a list after element of order I

I'm trying to implement a predicate that replaces NumElm elements of a list after (and including) a given Index. For that I use another predicate that replaces an element of a list.
My code so far is:
replace([_|T], 0, X, [X|T]).
replace([H|T], I, X, [H|R]):-
I > -1,
NI is I-1,
replace(T, NI, X, R), !.
replace(L, _, _, L).
replaceX(_,_,0,_,_).
replaceX(Line,Index,NumElm,Elm,NLine) :-
replace(Line,Index,Elm,BLine),
Index1 is Index+1,
NumElm1 is NumElm-1,
replaceX(BLine,Index1,NumElm1,Elm,Nline).
With that code, only the first element, the one of order Index, is replaced.
Any ideas?
Thanks in advance.
[EDIT] The result of the previous code was just 'yes'. The one that replaced the first element was the following:
replace([_|T], 0, X, [X|T]).
replace([H|T], I, X, [H|R]):-
I > -1,
NI is I-1,
replace(T, NI, X, R), !.
replace(L, _, _, L).
replaceX(_,_,0,_,_).
replaceX(Line,Index,NumElm,Elm,NLine) :-
replace(Line,Index,Elm,NLine),
Index1 is Index+1,
NumElm1 is NumElm-1,
replaceX(NLine,Index1,NumElm1,Elm,Nline).
I think you need to define the first clause of replaceX with:
replaceX(A,_,0,_,A):-!.
The reasoning behind this is explained by how _ works: it names an anonymous variable, and each instance of _ names a different variable. Here's an explanation. The cut, on the other hand, helps you get rid of undesired backtracking.
I think Nline in the last line should be NLine. Also you're lacking a dot at the end of the second replace clause.
Edit:
replace([_|T], 0, X, [X|T]).
replace([H|T], I, X, [H|R]):-
I > -1,
NI is I-1,
replace(T, NI, X, R), !.
replace(L, _, _, L).
replaceX(A,_,0,_,A):- !.
replaceX(Line,Index,NumElm,Elm,NLine) :-
replace(Line,Index,Elm,BLine),
Index1 is Index+1,
NumElm1 is NumElm-1,
replaceX(BLine,Index1,NumElm1,Elm,NLine).
Example input:
?- replaceX([0,1,2,3,4,5,6],2,4,a,R).
R = [0,1,a,a,a,a,6].
Isn't that the expected result?
handling numeric indexing can be tedious in Prolog, I would write
replace(L, From, To, X, R) :-
findall(S, (nth0(I,L,E), (I>=From, I<To ->S = X ; S = E)), R).
that yields
?- replace([0,1,2,3,4,5,6], 2,4,a, R).
R = [0, 1, a, a, 4, 5, 6].
Here's one way:
replace( As , _ , 0 , _ , As ) . % special case: nothing left to replace.
replace( [A|As] , P , N , X , [A|Bs] ) :- % otherwise,
P > 0 , % - if the position counter is greater than zero,
P1 is P-1 , % - decrement it, stow the current item to the result list
replace( As , P1 , N , X , Bs ) % - and recurse down
. %
replace( [_|As] , 0 , N , X , [X|Bs] ) :- % otherwise, if the position count is decremented to zero
N > 0 , % - but the length counter is greater than zero,
N1 is N-1 , % - decrement it, stow X in the result list
replace( As , 0 , N1 , X , Bs ) % - and recurse down.
. %