Prolog: why my predicate returns false? - prolog

so I wrote a predicate that counts how many times an element occurs in a list of lists.
count([], _, 0). #base case
count([[Elem|Rest]|OtherLists], Elem, Count) :- #Elem is the head of sublist
!,
count([Rest|OtherLists], Elem, NewCount),
succ(NewCount, Count).
count([[_|Rest]|OtherLists], Elem, Count) :- #Elem is not the head of sublist
count([Rest|OtherLists], Elem, Count).
count([[]|OtherLists], Elem, Count) :- #Head sublist is an empty list
count(OtherLists, Elem, Count).
Now that if I query the predicate with the following:
count([[1,2,3],[4,1,5],[4,6,1]], 1, X).
it returns X = 3, which is correct, but it will also say 'false' if I continue with the query.
So it counts elements correctly, but I cannot use this predicate inside other predicates since it eventually returns FALSE.
What am I doing wrong?

When Prolog encounters a "choice point" (a place in the code where it can come back to seek more possible solutions) in the process of finding a solution, it will show the solution and prompt you for more possible solutions. If it finds no more, it displays "false". This is not any kind of error in your logic. It's the way Prolog works.
It is not always desirable to remove the choice point. It depends upon what your goals are for the predicate. The danger in removing choice points using cuts is that the choice point may be a path to valid alternative solutions, and the cut prevents your program from finding those solutions.
Let's try your updated program with the new proposed cut in your answer:
| ?- count([[1,2,3],[4,1,5],[4,6,1]], 1, X).
X = 3
yes
| ?- count([[1,2,1,3],[4,1,5],[4,6,1]], 1, X).
X = 4
yes
| ?- count([[1,2,1,3],[4,1,5],[4,6,1],[1]], 1, X).
X = 5
So far, so good. These look like complete and correct answers. I believe your additional cut (and including your original cut) will yield a correct answer as long as the first argument is fully bound with no variables. Let's try a more interesting query:
2 ?- count([[A,2,B],[C,1,D]], 1, X).
A = B, B = C, C = D, D = 1,
X = 5.
3 ?-
The predicate found one solution. However, aren't there more? What about this one?
A = _ % something other than 1
B = C, C = D, D = 1,
X = 4.
This would be a correct solution as well, but the predicate fails to find it.
Also, what about this query?
2 ?- count([[1,2,1,3],[4,1,5],[4,6,1],[1]], E, X).
E = 1,
X = 5.
3 ?-
Again, only one solution found. But aren't there more? What about E = 4 and X = 2?
If we remove all of the cuts from the original predicate in an attempt to get all of the correct solutions, then we get incorrect solutions as well:
2 ?- count([[1,2],[3,1,4],[1]], 1,X).
X = 3 ;
X = 2 ;
X = 2 ;
X = 1 ;
X = 2 ;
X = 1 ;
X = 1 ;
X = 0 ;
false.
2 ?- count([[1,2,1,3],[4,1,5],[4,6,1],[1]], E, X).
E = 1,
X = 5 ;
E = 1,
X = 4 ;
E = 1,
X = 3 ;
...
So if more generality is desired, a more effective solution needs to be constructed.
count_occurrences_lol([], _, 0).
count_occurrences_lol([List|Lists], X, Count) :-
count_occurrences(List, X, C1), % Count occurrences in this list
count_occurrences_lol(Lists, X, C2), % Count occurrences in remaining sublists
Count is C1 + C2. % Total the counts
count_occurrences([], _, 0).
count_occurrences([X|Xs], X, Count) :-
count_occurrences(Xs, X, C1),
Count is C1 + 1.
count_occurrences([X1|Xs], X, Count) :-
dif(X1, X),
count_occurrences(Xs, X, Count).
Now we get the following:
3 ?- count_occurrences_lol([[1,2],[3,1,4],[1]], 1,X).
X = 3 ;
false.
Just one solution, as expected. And the following:
5 ?- count_occurrences_lol([[A,2,B],[C,1,3]], 1, X).
A = B, B = C, C = 1,
X = 4 ;
A = B, B = 1,
X = 3,
dif(C, 1) ;
A = C, C = 1,
X = 3,
dif(B, 1) ;
A = 1,
X = 2,
dif(B, 1),
dif(C, 1) ;
B = C, C = 1,
X = 3,
dif(A, 1) ;
B = 1,
X = 2,
dif(A, 1),
dif(C, 1) ;
C = 1,
X = 2,
dif(A, 1),
dif(B, 1) ;
X = 1,
dif(A, 1),
dif(B, 1),
dif(C, 1) ;
false.
3 ?- count_occurrences_lol([[1,2,1,3],[4,1,5],[4,6,1],[1]], E, X).
E = 1,
X = 5 ;
E = 2,
X = 1 ;
E = 3,
X = 1 ;
E = 4,
X = 2 ;
E = 5,
X = 1 ;
E = 6,
X = 1 ;
X = 0,
dif(E, 1),
dif(E, 1),
dif(E, 6),
dif(E, 4),
dif(E, 5),
dif(E, 1),
dif(E, 4),
dif(E, 3),
dif(E, 1),
dif(E, 2),
dif(E, 1).
4 ?-
Several possible solutions as expected.

Ok, it looks like it was backtracking on the part where 'Elem is not the head of sublist', and I was able to fix it by changing it to:
count([[_|Rest]|OtherLists], Elem, Count) :- #Elem is not the head of sublist
!,
count([Rest|OtherLists], Elem, Count).
If anyone can confirm whether this is a correct solution. Thanks

Related

Incrementing value on backtrack

how can I do increment on backtracking ... so that goal(S) receives incremented number .. every time it fails on the next run I want to get the next number
S1 is S + 1,goal(S1)
does not work, because :
?- S=0, S1 is S+1.
S = 0,
S1 = 1.
?- S=0,between(1,3,_), S1 is S+1.
S = 0,
S1 = 1 ;
S = 0,
S1 = 1 ;
S = 0,
S1 = 1.
this work
%%counting
baz(..,C) :- .... arg(...), Y is X + 1, nb_setarg(...), goal(Y), ...
foo(..C) :- ....baz(....,C)..., foo(...C).
%%counter
blah :- ....foo(....,counter(0))...
this is not working, i think cause the recursive foo() would force baz() to initialize counter(0)... but i'm good with #sligo solution above
baz(..) :- C = counter(0), .... arg(...), Y is X + 1, nb_setarg(...), goal(Y), ...
foo(..) :- ....baz(....)..., foo(...).
so that goal(S) receives incremented number .. every time it fails on the next run I want to get the next number
That's what between/3 does? Every time on backtracking it makes the next number:
goal(X) :-
write('inside goal, X is '),
write(X),
nl.
test :-
between(0, 3, S),
goal(S).
e.g.
?- test.
inside goal, X is 0
true ;
inside goal, X is 1
true ;
inside goal, X is 2
true ;
inside goal, X is 3
true ;
Edit: From the help for between/3:
between(+Low, +High, ?Value)
Low and High are integers, High >=Low. If Value is an integer,
Low =<Value =<High. When Value is a variable it is successively
bound to all integers between Low and High. If High is inf or
infinite between/3 is true iff Value >=Low, a feature that is
particularly interesting for generating integers from a certain value.
(And see the comments on the help page by LogicalCaptain)
Use non-backtrackable destructive assignment predicate nb_setarg/3:
?- C = counter(0), between(1, 3, _), arg(1, C, X), Y is X + 1, nb_setarg(1, C, Y).
C = counter(1),
X = 0,
Y = 1 ;
C = counter(2),
X = 1,
Y = 2 ;
C = counter(3),
X = 2,
Y = 3.
Alternatives:
foo(C) :-
between(1, inf, C),
goal(C),
!.
baz(C) :-
C = counter(0),
repeat,
arg(1, C, X),
Y is X + 1,
nb_setarg(1, C, Y),
goal(Y),
!.
goal(X) :-
X > 9.
Examples:
?- foo(C).
C = 10.
?- baz(C).
C = counter(10).

Prolog: Creating a frequency list of another list

So, I've written a program that reads input from a .txt file in the form of 2 integers and a list of integers: the first integer is the length of the list, the second is the number of different elements, and the list is the list in question.
I then want to create a list of frequencies for the elements, like so:
List = [1, 2, 3, 1, 3, 2, 3, 1],
FreqList = [3, 2, 3].
Here is my code:
% Create random list
createList(List) :-
length(List, 10),
maplist(random(0,4), List).
% Count the frequency of an element:
countElement(_, [], 0) :- !.
countElement(_, [], _).
countElement(Element, [Element|Tail], Counter) :-
countElement(Element, Tail, Counter2),
Counter is Counter2 + 1.
countElement(Element, [_|Tail], Counter) :-
countElement(Element, Tail, Counter).
% Create frequency list:
createFreqList(_, _, Numbers, [], CurrentNumber) :-
Numbers = CurrentNumber.
createFreqList(List, Length, Numbers, [Head|Tail], CurrentNumber) :-
Numbers \= CurrentNumber,
countElement(CurrentNumber, List, Head),
CurrentNumber2 is CurrentNumber + 1,
createFreqList(List, Length, Numbers, Tail, CurrentNumber2).
frequency(List, FreqList) :-
createList(List),
Numbers2 is 4,
createFreqList(List, 10, Numbers2, FreqList, 1).
So, on first execution the program runs ok, and it outputs the correct frequency list. However, if I input ';', instead of giving me 'false' it runs again, outputing a wrong frequency list, and that just repeats for as long as I press ';'.
I would probably do something like this:
frequencies(Xs, Fs) :-
msort(Xs,Sorted),
glob( Sorted, [], Fs ).
glob( [], Fs, Fs ).
glob( [X|Xs], [X:N|Ts], Fs ) :-
!,
N1 is N+1,
glob(Xs, [X:N1|Ts], Fs ).
glob( [X|Xs], Ts, Fs ) :-
glob(Xs, [X:1|Ts], Fs).
That used msort/2 to put the list in sequence.The resulting list is in descending sequence by key value — [ 3:123, 2:25, 1:321 ].
You could also do something like this:
frequencies(Xs, Fs) :- frequencies( Xs, [], Fs ).
frequencies( [], Fs, Fs ).
frequencies( [X|Xs], Ts, Fs ) :-
tote( X, Ts, T1),
frequencies(Xs, T1, Fs).
tote( X, Ts, Fs ) :-
append( Pfx, [X:N|Sfx], Ts),
!,
N1 is N+1,
append( Pfx, [X:N1|Sfx], Fs).
tote( X, Ts, [X:1|Ts] ).
I suspect that a one-time sort of the original list is probably going to be faster than repeated scans of the accumulator list.
Just in case you don't want to reinvent the wheel.
There is a quasi standard called library(aggregate). But library(aggregate) can be also implemented on top of the ISO core standard bagof/3, which also gets you there:
Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.6)
?- aggregate(count, member(X,[1, 2, 3, 1, 3, 2, 3, 1]), R).
X = 1,
R = 3 ;
X = R, R = 2 ;
X = R, R = 3.
?- bagof(hit, member(X,[1, 2, 3, 1, 3, 2, 3, 1]), L), length(L, R).
X = 1,
L = [hit, hit, hit],
R = 3 ;
X = R, R = 2,
L = [hit, hit] ;
X = R, R = 3,
L = [hit, hit, hit].
Or in another Prolog system:
Jekejeke Prolog 3, Runtime Library 1.3.7 (May 23, 2019)
?- use_module(library(advanced/aggregate)).
% 3 consults and 0 unloads in 110 ms.
Yes
?- use_module(library(basic/lists)).
% 0 consults and 0 unloads in 0 ms.
Yes
?- aggregate(count, member(X,[1, 2, 3, 1, 3, 2, 3, 1]), R).
X = 1,
R = 3 ;
X = 2,
R = 2 ;
X = 3,
R = 3
?- bagof(hit, member(X,[1, 2, 3, 1, 3, 2, 3, 1]), L), length(L, R).
X = 1,
L = [hit,hit,hit],
R = 3 ;
X = 2,
L = [hit,hit],
R = 2 ;
X = 3,
L = [hit,hit,hit],
R = 3

Prolog result not multiplying

I have the following prolog program:
square([H|T], X) :-
squareCompare(T, H, X).
squareCompare([], X, X * X ).
squareCompare([H|T], V, Result) :-
(V * V) < (H * H),
squareCompare(T, V, Result);
(V * V) > (H * H),
squareCompare(T, H, Result).
When I enter:
square([7, 5, 2], Result).
I get Result = 2 * 2, what I want is Result = 4.
This program searches for the smallest square of the element in the list.
Besides the lack of arithmetic evaluation (is/2) as pointed out in the comments there's also an issue with using </2 and >/2: your predicate doesn't work for list with consecutive repetitions, e.g.:
?- square([7,7],X).
false.
where the expected result would be 49. You can remedy that by replacing </2 by =</2 or >/2 by >=/2 in your recursive rule of squareCompare/3:
squareCompare([], X, Y) :-
Y is X*X.
squareCompare([H|T], V, Result) :-
(V * V) < (H * H),
squareCompare(T, V, Result);
(V * V) >= (H * H),
squareCompare(T, H, Result).
Now the predicate yields the desired result:
?- square([7,7],X).
X = 49.
Following another suggestion in the comments, you could opt to use CLP(FD) to make the predicate work both ways. In that case the predicate resembles a true relation so it'd be appropriate to give it a more descriptive name that reflects this fact, say list_minsquare/2. And since you are interested in the smallest square, why not pass around the squares as arguments rather than the numbers? Worst case: the root of the smallest square is the last list element, then there's no difference. Best case: the root of the smallest square is the first list element, then you only calculate it once instead of length-of-list times. Putting all this together:
:- use_module(library(clpfd)).
list_minsquare([H|T],X) :-
S #= H*H,
list_square_minsquare(T,S,X).
list_square_minsquare([],S,S).
list_square_minsquare([H|T],S,Result) :-
S #< (H*H),
list_square_minsquare(T,S,Result).
list_square_minsquare([H|T],S,Result) :-
H2 #= (H*H),
S #>= H2,
list_square_minsquare(T,H2,Result).
Now let's see some action. Your example query yields the desired result:
?- list_minsquare([7,4,2],X).
X = 4.
Consecutive repetitions also don't cause troubles:
?- list_minsquare([7,7],X).
X = 49.
Partially instantiated lists lead to all possible solutions being produced:
?- list_minsquare([7,Y,2],X).
X = 4, % <- 1st answer: X=4 if
Y^2#=_G670,
_G670 in 50..sup ; % Y^2 is between 50 and sup
Y in -1..1, % <- 2nd answer: if Y in -1..1
Y^2#=X, % then X=Y^2
X in 0..1 ;
X = 4, % <- 3rd answer: X=4
Y in -7.. -1\/1..7, % if Y in -7..-1 or 1..7
Y^2#=_G1754,
_G1754 in 4..49. % and Y^2 in 4..49
In the above example there are three possibilities for Y none of which has a unique solution, hence you get residual goals in the answers. If you wish to get concrete solutions you can constrain the range of Y and ask for concrete numbers with label/1:
?- Y in 0..3, list_minsquare([7,Y,2],X), label([Y]).
Y = X, X = 0 ;
Y = X, X = 1 ;
Y = 2,
X = 4 ;
Y = 3,
X = 4.
The most general query works as well. However, it is listing the solutions in an unfair manner:
?- list_minsquare(L,X).
L = [_G97], % <- 1st solution
_G97^2#=X,
X in 0..sup ;
L = [_G266, _G269], % <- 2nd solution
_G266^2#=X,
X in 0..sup,
X+1#=_G309,
_G309 in 1..sup,
_G332#>=_G309,
_G332 in 1..sup,
_G269^2#=_G332 ;
L = [_G494, _G497, _G500], % <- 3rd solution
_G494^2#=X,
X in 0..sup,
X+1#=_G540,
X+1#=_G552,
_G540 in 1..sup,
_G575#>=_G540,
_G575 in 1..sup,
_G500^2#=_G575,
_G552 in 1..sup,
_G620#>=_G552,
_G620 in 1..sup,
_G497^2#=_G620 ;
.
.
.
You only get one solution for every list length before moving on to the next length. You can get a fair ordering by prefixing a goal length/2 in the query. Then you'll get all possibilities for every list length before moving on:
?- length(L,_), list_minsquare(L,X).
L = [_G339], % <- 1st solution: list with one element
_G339^2#=X,
X in 0..sup ;
L = [_G1036, _G1039], % <- 2nd solution: list with two elements
_G1036^2#=X, % X is square of 1st element
X in 0..sup,
X+1#=_G1079,
_G1079 in 1..sup,
_G1102#>=_G1079,
_G1102 in 1..sup,
_G1039^2#=_G1102 ;
L = [_G935, _G938], % <- 3rd solution: list with two elements
_G935^2#=_G954,
_G954 in 0..sup,
_G954#>=X,
X in 0..sup,
_G938^2#=X ; % X is square of 2nd element
.
.
.
Of course you can also constrain and label the numbers in the list for the above query and you'll get concrete numbers in the still infinitely many solutions (since there are infinitely many list lengths).
?- length(L,_), L ins 1..2, list_minsquare(L,X), label(L).
L = [1],
X = 1 ;
L = [2],
X = 4 ;
L = [1, 2],
X = 1 ;
L = [1, 1],
X = 1 ;
L = [2, 1],
X = 1 ;
L = [2, 2],
X = 4 ;
L = [1, 2, 2],
X = 1 ;
L = [1, 2, 1],
X = 1 ;
L = [1, 1, 2],
X = 1 ;
L = [2, 1, 2],
X = 1 ;
.
.
.

How to find two numbers where a restriction is applied

Let's say that I want to find two numbers where the sum of these are 8, are from 1-9 and must be different(it is obvious that these numbers are (7,1),(6,2),etc).So I wrote.
dif_list([H|T]):- \+ member(H,T),dif_list(T).
dif_list([]).
check1_9([H|T]):-H>=1,H=<9,check1_9(T).
check1_9([]).
find_number([A,B],N) :- N =:= A+B,dif_list([A,B]),check1_9([A,B]).
Afterwards I will ask prolog
?-find_number([A,B],8).
ERROR: =:=/2: Arguments are not sufficiently instantiated
My goal is that prolog will print for me the results.For example:
?-find_number([A,B],8).
A = 7,
B = 1 ;
A = 6,
B = 2 ;
...
The best way to handle this kind of problem in Prolog is to use the CLP(FD) library:
:- [library(clpfd)].
sum_of(A, B, Sum) :-
A #> 0,
B #> 0,
A + B #= Sum.
?- sum_of(A, B, 8), label([A, B]).
A = 1,
B = 7 ;
A = 2,
B = 6 ;
A = 3,
B = 5 ;
A = B, B = 4 ;
A = 5,
B = 3 ;
A = 6,
B = 2 ;
A = 7,
B = 1.
?-
If you want the addends to be unique, you can further constrain it:
sum_of(A, B, Sum) :-
A #> 0,
B #>= A,
A + B #= Sum.
There's really no need to use a list to manage the variables A and B, but you can if you wish: sum_of([A,B], Sum).
Prolog is not that declarative: there are indeed answer set programming (ASP) or constraint logic programming (clp) languages where you can simply define a set of constraints and a finite domain solver aims to solve it (but these will take considerable time).
I would suggest that you define your program as follows:
find_number(A,B,N) :-
member(A,[1,2,3,4,5,6,7,8,9]),
member(B,[1,2,3,4,5,6,7,8,9]),
N is A+B,
A \= B.
Here member/2 will instantiate A and B to values that are provided by the list, so 1..9, next you use is/2 to calculate the sum and verify that the sum is equal to N. You can only call N is A+B if A and B are given a proper value. Finally we say A \= B (A is not equal to B).
When you run this predicate, it produces:
?- find_number(A,B,8).
A = 1,
B = 7 ;
A = 2,
B = 6 ;
A = 3,
B = 5 ;
A = 5,
B = 3 ;
A = 6,
B = 2 ;
A = 7,
B = 1 ;
false.
You can however also query with A and B already filled in, or one of them filled in, or where the sum is left open. So:
?- find_number(A,2,8).
A = 6 ;
false.
or:
?- find_number(A,2,N).
A = 1,
N = 3 ;
A = 3,
N = 5 ;
A = 4,
N = 6 ;
A = 5,
N = 7 ;
A = 6,
N = 8 ;
A = 7,
N = 9 ;
A = 8,
N = 10 ;
A = 9,
N = 11 ;
false.

Understanding prolog [lists]

I am to write a program that does this:
?- pLeap(2,5,X,Y).
X = 2,
Y = 3 ;
X = 3,
Y = 4 ;
X = 4,
Y = 5 ;
X = 5,
Y = 5 ;
false.
(gives all pairs X,X+1 between 2 and 5, plus the special case at the end).
This is supposedly the solution. I don't really understand how it works, could anyone guide me through it?
pLeap(X,X,X,X).
pLeap(L,H,X,Y) :-
L<H,
X is L,
Y is X+1.
pLeap(L,H,X,Y) :-
L=<H,
L1 is L+1,
pLeap(L1,H,X,Y).
I'd do it simply like this:
pLeap(L,H,X,Y) :-
X >= L,
X =< H,
Y is X+1.
Why doesn't it work (ignoring the special case at the end)?
You could use library clpfd for you problem.
:- use_module(library(clpfd)).
pLeap(L,H,X,Y) :-
X in L..H,
Y #= min(H, X+1),
label([X]).
Here is the output:
?- pLeap(2,5,X,Y).
X = 2,
Y = 3 ;
X = 3,
Y = 4 ;
X = 4,
Y = 5 ;
X = 5,
Y = 5.
The >= and =< operators don't instantiate their arguments, and you can only use them once the arguments have already been instantiated.
Put another way, in the given solution, X and Y are given values with is, and the < and =< operators are only used on L and H, whose values are given by the user. (On the given solution, try pLeap(L,H,2,3) and you'll get the same problem as you're having.)
In your case, though, you try to use >= and =< on X, which has no value yet, and so the interpreter complains.

Resources