How can I compare the value of two predicates prolog - list

I have three predicates that return half the number of elements
in a list, the number of ones and the number of zeros.
I need to write a predicate that returns false if half the number of elements is smaller than the numbers of zeros on a list and returns false if half the number of elements is smaller than the numbers of ones on a list
this is what i did, but it's not working:
apply(L,R):- number_elements(L,0) < number_zeros(L,0),!,fail.
apply(L,R):- number_elements(L,0) < number_ones(L,0),!,fail.
My number_elements is:
number_elements(List, HalfCount) :- length(List, N), HalfCount is N div 2.
My number_ones is equal to my number_zeros:
number_ones([], 0).
number_ones([H|T], N) :-
number_ones(T, X),
( H == 1
-> N is X+1
; N is X
).
Thanks!

In Prolog, your predicates cannot return values other than true/false, so you cannot write queries such as predicate1 < predicate2. If you want to "return a number", you encode it in the variables of your predicates. You wrote you already have the predicates number_elements and number_zeros / number_ones defined. I assume that these predicates are "returning" the number via their second variable, such that e.g.
?- number_zeros([0,1,2], 0).
false.
?- number_zeros([0,1,2], 1).
true .
?- number_zeros([0,1,2], N).
N = 1 .
The comparison you wanted can now be written by calling your predicates with variables for their second arguments and then comparing these variables:
apply(L) :-
length(L, N),
number_zeros(L, M0),
number_ones(L, M1),
H is N//2,
H >= M0,
H >= M1.

Related

How can I get half the number of elements on a list prolog

I have this predicate that gives me the number of elements in a list.
get_elements([],0).
get_elements([_|Tail], N) :- get_elements(Tail, N1), N is N1 + 1.
?- get_elements([1,1,1,1,1,1],N).
N = 6.
But instead 6 i want 3. How can I change my predicate in order to do that?
Thanks!
You haven't said what you want to happen if the list has an odd number of elements. But I'll assume you want a result in that case.
A brute force but simple approach is to use length/2:
count_half(List, HalfCount) :- length(List, N), HalfCount is N div 2.
For a list with an odd number of elements, it will give the half of the number of elements minus 1 (e.g., 7 elements will yield result of 3).
A simple, recursive approach (and that is more instructive regarding list processing) is to change your implementation a little:
count_half([], 0).
count_half([_,_|Tail], N) :-
count_half(Tail, N1),
N is N1 + 1.
This will count each pair of elements. The only drawback is that if there are an odd number of elements, it will result in failure. That can be remedied with one additional base case:
count_half([], 0).
count_half([_], 0).
count_half([_,_|Tail], N) :-
count_half(Tail, N1),
N is N1 + 1.

Counting elements in list ignoring adjacent duplicates

count([], 0).
count(L, N) :- countDistinct(L, 0).
countDistinct([H,H1|T], N) :-
(H == H1,
countDistinct([H1|T], N));
(H =\= H1, N1 is N+1,
countDistinct([H1|T], N1)).
My approach was to obviously have the trivial base case, and then call a new predicate countDistinct with the initial N as being 0. Then, N is incremented only if the adjacent elements are distinct.
Is my idea of calling countDistinct like this wrong? How should I adapt it.
Since you are trying to solve this with recursion this answer will take that approach. Also this answer will only cover the mode of a list being bound and count being unbound and will not use cuts to remove choice points. You can
enhance the code if desired.
When creating recursive predicates for list I typically start with a template like:
process_list([H|T],R) :-
process_item(H,R),
process_list(T,R).
process_list([],R).
with the recursive case:
process_list([H|T],R) :-
process_item(H,R),
process_list(T,R).
and the base case:
process_list([],R).
The list is deconstructed using [H|T] where H is for head of list and T is for tail of list. R is for result.
The head item is processed using:
process_item(H,R)
and the tail of the list is processed using:
process_list(T,R)
Since this requires processing two adjacent items in the list modifications are needed:
process_list([H1,H2|T],R) :-
process_item(H1,H2,R),
process_list([H2|T],R).
process_list([],0).
process_list([_],1).
NB There are now two base cases instead of one. Just because recursive predicates are typically one recursion clause and one base case clause does not mean they are always one recursive clause and one base case clause.
Next update the process_item
process_item(I1,I1,N,N).
process_item(I1,I2,N0,N) :-
I1 \== I2,
N is N0 + 1.
Since is/2 is used to increment the count, a count state needs to be passed in, updated and passed out, thus the variables, N0 and N.
When using state variable or threaded variables, the naming convention is to append 0 to the input value, have no number appended to the output value and increment the appended number in the same clause as the threading progresses.
When the items are the same the count is not incremented which is done using:
process_item(I1,I1,N,N).
When the items are different the count is incremented which is done using:
process_item(I1,I2,N0,N) :-
I1 \== I2,
N is N0 + 1.
In the process of changing process_item, R became N0 and N so this requires a change to process_list
process_list([H1,H2|T],N0,N) :-
process_item(H1,H2,N0,N1),
process_list([H2|T],N1,N).
and to use this a helper predicate is added so that the signature of the original predicate can stay the same.
count(L,N) :-
process_list(L,0,N).
The full code
count(L,N) :-
process_list(L,0,N).
process_list([H1,H2|T],N0,N) :-
process_item(H1,H2,N0,N1),
process_list([H2|T],N1,N).
process_list([],N,N).
process_list([_],N0,N) :-
N is N0 + 1.
process_item(I1,I1,N,N).
process_item(I1,I2,N0,N) :-
I1 \== I2,
N is N0 + 1.
Test cases
:- begin_tests(count).
test(1,[nondet]) :-
count([],N),
assertion( N == 0 ).
test(2,[nondet]) :-
count([a],N),
assertion( N == 1 ).
test(3,[nondet]) :-
count([a,a],N),
assertion( N == 1 ).
test(4,[nondet]) :-
count([a,b],N),
assertion( N == 2 ).
test(5,[nondet]) :-
count([b,a],N),
assertion( N == 2 ).
test(6,[nondet]) :-
count([a,a,b],N),
assertion( N == 2 ).
test(7,[nondet]) :-
count([a,b,a],N),
assertion( N == 3 ).
test(8,[nondet]) :-
count([b,a,a],N),
assertion( N == 2 ).
:- end_tests(count).
Example run
?- run_tests.
% PL-Unit: count ........ done
% All 8 tests passed
true.
Solution using DCG
% Uses DCG Semicontext
lookahead(C),[C] -->
[C].
% empty list
% No lookahead needed because last item in list.
count_dcg(N,N) --> [].
% single item in list
% No lookahead needed because only one in list.
count_dcg(N0,N) -->
[_],
\+ [_],
{ N is N0 + 1 }.
% Lookahead needed because two items in list and
% only want to remove first item.
count_dcg(N0,N) -->
[C1],
lookahead(C2),
{ C1 == C2 },
count_dcg(N0,N).
% Lookahead needed because two items in list and
% only want to remove first item.
count_dcg(N0,N) -->
[C1],
lookahead(C2),
{
C1 \== C2,
N1 is N0 + 1
},
count_dcg(N1,N).
count(L,N) :-
DCG = count_dcg(0,N),
phrase(DCG,L).
Example run:
?- run_tests.
% PL-Unit: count ........ done
% All 8 tests passed
true.
Better solution using DCG.
Side note
In your example code is the use of the ;/2
A typical convention when forammting code with ;/2 is to format as such
(
;
)
so that the ; stands out.
Your code reformatted
countDistinct([H,H1|T], N) :-
(
(
H == H1,
countDistinct([H1|T], N)
)
;
(
H =\= H1,
N1 is N+1,
countDistinct([H1|T], N1)
)
).

Prolog: Sum one element of a list at a time

I'm new to Prolog and have decided to try to solve a problem in which I have a sequence of symbols that each have the value 1 or -1. What I need is to add them all together, one element at a time, and extract at which index the sum for the first time drops below 0. Since I'm coming from an imperative background, I'm imagining a count variable and a for-loop, but obviously I can't do that in Prolog.
value('(', 1).
value(')', -1).
main(R) :- readFile("input", R), ???
readFile(Path, R) :-
open(Path, read, File),
read_string(File, _, Str),
stringToCharList(Str, Xs),
maplist(value, Xs, R).
stringToCharList(String, Characters) :-
name(String, Xs),
maplist(toChar, Xs, Characters ).
toChar(X, Y) :- name(Y, [X]).
As you can see, all that I've really managed so far is to read the file that contains the sequence, and convert it to 1s and -1s. I have no idea where to go from here. I suppose the problem is three-fold:
I need to iterate over a list
I need to sum each element in the list
I need to return a certain index
Any suggestions? Can I somehow cut off the list where iteration would have dropped the sum below zero, and just return the length?
I'll use a principle in Prolog of an auxiliary variable to act as a counter until the conditions reach what we want. Then the auxiliary counter is unified with a variable at that point in the base case.
I'm assuming here, blindly, that your code works as stated. I did not test it (that's up to you).
main(IndexAtZeroSum) :- readFile("input", R), index_at_zero_sum(R, IndexAtZeroSum).
readFile(Path, R) :-
open(Path, read, File),
read_string(File, _, Str),
stringToCharList(Str, Xs),
maplist(value, Xs, R).
stringToCharList(String, Characters) :-
name(String, Xs),
maplist(toChar, Xs, Characters ).
toChar(X, Y) :- name(Y, [X]).
% The following predicate assumes indexing starting at 0
index_at_zero_sum([V|Vs], IndexAtZeroSum) :-
index_at_zero_sum(Vs, V, 0, IndexAtZeroSum).
% When sum is zero, Index is what we want
index_at_zero_sum(_, 0, Index, Index).
index_at_zero_sum([V|Vs], Sum, CurIndex, Index) :-
S is Sum + V,
NextIndex is CurIndex + 1,
index_at_zero_sum(Vs, S, NextIndex, Index).
index_at_zero_sum/2 provides the index for the given list where the sum becomes zero. It does so by using an auxiliary predicate, index_at_zero_sum/4, starting with a sum at the first value (the sum being the value itself) and the current index starting at 0. So the 2nd argument is the sum at index 0. Subsequent calls to index_at_zero_sum/4 increment the index and accumulate the sum until the sum becomes 0. At that point, the base case succeeds and unifies the 4th argument with the current index. If the sum never becomes 0 before the list becomes empty, the predicate fails.
You can also avoid reading the entire file and creating a numeric list by using get_char/2:
index_at_zero_sum(Path, Index) :-
open(Path, read, File),
get_char(File, C),
value(C, V),
( index_at_zero_sum(File, V, 0, Index)
-> close(File)
; close(File),
fail
).
index_at_zero_sum(_, 0, Index, Index).
index_at_zero_sum(File, Sum, CurIndex, Index) :-
get_char(File, C),
value(C, V),
S is Sum + V,
NewIndex is CurIndex + 1,
index_at_zero_sum(File, S, NewIndex, Index).

Index of first element greater than X (Prolog)

I am aware on how to find the index of a specific element in Prolog but is there a way to find the index of the first instance of a number greater than say X. For instance, say I have a list of all ones but there is a random number greater than one somewhere in the list. How could I go about finding the index of the first instance of a number greater than 1? I am really new to Prolog and am not too good at subgoals of predicates.
You want to write a relation between a list an index and a value. Let's call it list_1stindex_gt/3. It is opportune to have a fourth argument to keep track of the current index. However, it would be nice to not bother the user with this accumlator, so you could use and auxiliary predicate with an additional argument for the current index, let's call it list_1stindex_gt_/4. Assuming you want to start counting the indices at 1 (otherwise change the fourth argument to 0) you can define list_1stindex_gt/3 like so:
:-use_module(library(clpfd)).
list_1stindex_gt(L,I,GT) :-
list_1stindex_gt_(L,I,GT,1).
For list_1stindex_gt_/4 you have 2 cases:
The head of the list is greater than the third argument: Then you know the desired index.
The head of the list is smaller or equal to the third argument: Then you increment the accumlator by 1 and continue the search in the tail of the list.
You can write that in Prolog like so:
list_1stindex_gt_([X|Xs],I,GT,I) :- % case 1
X #> GT.
list_1stindex_gt_([X|Xs],I,GT,Acc0) :- % case 2
X #=< GT,
Acc1 #= Acc0+1,
list_1stindex_gt_(Xs,I,GT,Acc1).
Example queries: At which index is the first element greater than 1 in the given list?
?- list_1stindex_gt([1,1,1,1,5,1,1,2],I,1).
I = 5 ? ;
no
At which index can the first element greater than 1 be in a list of three variables?
?- list_1stindex_gt([A,B,C],I,1).
I = 1,
A in 2..sup ? ;
I = 2,
A in inf..1,
B in 2..sup ? ;
I = 3,
A in inf..1,
B in inf..1,
C in 2..sup ? ;
no
At which index can the first element greater than the variable X be in a list of three variables?
?- list_1stindex_gt([A,B,C],I,X).
I = 1,
X#=<A+ -1 ? ;
I = 2,
X#>=A,
X#=<B+ -1 ? ;
I = 3,
X#>=A,
X#=<C+ -1,
X#>=B ? ;
no
Furthermore, you could consider #mat's suggested improvement from this answer to a previous question by you: Following the idea behind (#<)/3 you can define (#>)/3 and then define list_1stindex_gt_/4 using if_/3 like so:
:-use_module(library(clpfd)).
#>(X, Y, T) :-
zcompare(C, X, Y),
greater_true(C, T).
greater_true(<, false).
greater_true(>, true).
greater_true(=, false).
list_1stindex_gt(L,I,GT) :-
list_1stindex_gt_(L,I,GT,1).
list_1stindex_gt_([X|Xs],I,GT,Acc0) :-
if_(X #> GT,
(I #= Acc0),
(Acc1 #= Acc0+1, list_1stindex_gt_(Xs,I,GT,Acc1))).
This way the first query succeeds without leaving unnecessary choice points open:
?- list_1stindex_gt([1,1,1,1,5,1,1,2],I,1).
I = 5.
Here's a slightly different take on it:
:- use_module(library(clpfd)).
:- use_module(library(lists)).
:- asserta(clpfd:full_answer).
zs_first_greater(Zs, Index, Pivot) :-
append(Prefix, [E|_], Zs),
maplist(#>=(Pivot), Prefix),
E #> Pivot,
length([_|Prefix], Index). % 1-based index
Sample queries using SICStus Prolog 4.3.3:
| ?- zs_first_greater([1,1,1,2,1,1], I, 1).
I = 4 ? ;
no
| ?- zs_first_greater([1,1,1,2,1,1], I, 3).
no
| ?- zs_first_greater([], I, 3).
no
| ?- zs_first_greater([1,1,1,1,5,1,1,2], I, 1).
I = 5 ? ;
no
Thanks to clpfd we can also ask very general queries:
| ?- zs_first_greater([A,B,C,D], I, X).
I = 1,
A#>=X+1,
A in inf..sup,
X in inf..sup ? ;
I = 2,
A#=<X,
B#>=X+1,
A in inf..sup,
X in inf..sup,
B in inf..sup ? ;
I = 3,
A#=<X,
B#=<X,
C#>=X+1,
A in inf..sup,
X in inf..sup,
B in inf..sup,
C in inf..sup ? ;
I = 4,
A#=<X,
B#=<X,
C#=<X,
D#>=X+1,
A in inf..sup,
X in inf..sup,
B in inf..sup,
C in inf..sup,
D in inf..sup ? ;
no
To get any index in L, holding an element V greater than N, you could write:
?- L=[1,2,3,1,2,3],N=2, nth1(I,L,V),V>N.
and to limit to first instance:
?- L=[1,2,3,1,2,3],N=2, once((nth1(I,L,V),V>N)).
If you have library(clpfd) available, and your list has domain limited to integers, element/3 can play the same role as nth1/3, giving a bit more of generality
Here's a solution, as others pointed out it's not general, it will only work if the List of integers and the Threshold are ground terms.
As with most list processing predicates we need to think about it recursively:
Check the header of the list (its first element). If it's greater than the provided threshold then we are done.
Otherwise apply step 1. to the tail of the list (the list that remains after removing the header).
As you want the index of the element (as opposed to its actual value), we also need to keep track of the index and increment it in step 2. To do that we'll need a helper predicate.
%
% Predicate called by the user:
%
% The element of List at Index is the first one greater than Threshold.
%
idx_first_greater(List, Threshold, Index) :-
% here we use our helper predicate, initializing the index at 1.
idx_first_greater_rec(List, Threshold, 1, Index).
%
% Helper predicate:
%
% idx_first_greater_rec(List, Threshold, CurIdx, FoundIdx) :
% The element of List at FoundIndex is the first one greater
% than Threshold. FoundIdx is relative to CurIdx.
%
% Base case. If the header is greater than the Threshold then we are done.
% FoundIdx will be unified with CurIdx and returned back to the recursion stack.
idx_first_greater_rec([H|_], Threshold, Index, Index) :- H > Threshold, !.
% Recursion. Otherwise increment CurIdx and search in the tail of the list
idx_first_greater_rec([_|T], Threshold, CurIdx, FoundIdx) :-
NewIdx is CurIdx+1,
idx_first_greater_rec(T, Threshold, NewIdx, FoundIdx).
Notes:
The predicate will fail if the empty list is passed or if no element greater than Threshold was found. This looks to me like a good behavior.
This solution is tail-recursive, so it can be optimized by Prolog automatically.
Sample output:
?- idx_first_greater([1,1,1,2,1,1], 1, Idx).
Idx = 4 ;
false.
?- idx_first_greater([1,1,1,2,1,1], 3, Idx).
false.
?- idx_first_greater([], 3, Idx).
false.

Counting occurrences in list

I'm trying to create a rule that counts the number of occurrences of a certain element in a given list, what I've tried so far does not seem to work the way I expect:
The first argument here should be the list, the second one the element we are looking for, and the last one the number of occurrences:
%empty list should always return 0 occurences
count([],E,0) :- true.
%if our head is what we are looking for, count
count([E|T],E,N) :- count(T,E,N-1).
%otherwise, do not count
count([H|T],E,N) :- H \== E, count(T,E,N).
Here H is the head and T the tail of the given list.
The base case e.g. count([],1,N). returns N = 0 as expected, but as soon as the list is non empty, we always get false.:
?- count([1],1,N).
false.
?- count([1,2,1,3],1,N).
false.
Can anyone point out what I'm doing wrong?
Update:
It seems to work when replacing the second line with
count([E|T],E,N+1) :- count(T,E,N).
But I just cannot figure out why this is not equivalent to my first idea.
Then we get
?- count([1,2,1,3],1,N).
N = 0+1+1
which is correct.
Evaluation versus Unification
In Prolog =/2 is a unification operator. It does not evaluate a term as an expression even if the term might represent something numerically evaluable. Similarly, when you use count([E|T], E, N+1), Prolog does not evaluate the term N+1. To Prolog, that's just another term, which internally is represented as +(N, 1).
For a term to be interpreted and evaluated as a numeric expression, you need to use specific Prolog operators that will do that. As #SQB points out, one of these is is/2:
N = 1, N1 is N + 1.
This will result in N1 = 2. However this:
N = 1, N1 = N + 1.
Will result in: N1 = 1 + 1 (or equivalently, N1 = +(1, 1)).
There are also numeric comparison operators in Prolog that will also compute expressions. These are =:=/2, >/2, >=/2, </2 and =</2. So you will see the following:
1 + 2 =:= 3.
Will yield "true" since =:=/2 is specifically for comparing equality of evaluable numeric expressions. However:
1 + 2 = 3.
Will yield "false" because the term +(1,2) does not match (or more accurately, cannot be unified with) the term 3.
Argh! Arguments not sufficiently instantiated!
I've seen quite a few posts on SO regarding an error that their arguments are "not sufficiently instantiated". Many of these are in the use of is/2. As described above, is/2 will evaluate the expression in the 2nd argument and then unify that result with the first argument. The 2nd argument must be fully evaluable (all variables involved in the expression must be instantiated with a numeric value) or you'll get an error. Likewise, when using the expression comparisons, all of the variables in both arguments must be fully instantiated. Thus, if X is a variable that is unbound, the following will yield an "arguments not sufficiently instantiated" error:
9 is X * 3. % Will NOT yield X = 3, but will give an error
Y + 2 =:= X * 2. % Error if either X or Y are not instantiated
Y = 1, X = 2, Y + 2 =:= X * 2. % Yields "false" (fails) since 3 is not equal to 4
Y = 1, X = 2, Y + 2 < X * 2. % Yields "true" (succeeds) since 3 is less than 4
Y = 1, X = 2, X + 1 = Y + 2. % Yields "false" since +(2,1) doesn't unify with +(1,2)
When performing constraint logic on expressions, the tool to use is the CLP(FD) library. Thus:
X * 3 #= 6.
Will yield, X = 2.
The problem is that N+1 (or N-1) isn't evaluated, as can be seen by your second (working) example.
% empty list has 0 occurrences
count([], _, 0).
% if our head is what we are looking for, count
count([E|T], E, N) :-
N_1 is N - 1, % this is the important one
count(T, E, N_1).
% otherwise, do not count
count([H|T], E, N) :-
H \== E,
count(T, E, N).
is actually evaluates the equation, instead of unifying the N in your next call with N-1. That's why in your second example, you end up with N=0+1+1 instead of N=2.