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.
Related
I'm trying to slice a list, and create a result list that contains elements that fall between two indices, exclusive.
indexOf([Element|_], Element, 0). % We found the element
indexOf([_|Tail], Element, Index):-
indexOf(Tail, Element, Index1), % Check in the tail of the list
Index is Index1+1. % and increment the resulting index
less_than(0, 0).
less_than(X, N) :-
X < N.
greater_than(0, 0).
greater_than(X, N) :-
X > N.
slice([], 0, 0, []).
slice([H|T], I, N, R) :-
indexOf([H, T], H, Ind), % get the index of the H
(less_than(Ind, N),
greater_than(Ind, I), % check if that index is between I and N
slice(T, I, N, H|R); % if it is - call the slice again, but append the H to the result
slice(T, I, N, R)). % if it's not, just call the slice regularly with the rest of the items
For instance, slice([a,b,c,d], 0, 4, R) R should be [b,c].
Now this always fails but I'm not sure why.
Is it the base case, or is is the 'if-else' statement between the parenthesis?
I would like to accomplish this without using build-in predicates.
There are some fundamental flaws in your algorithm. You seem to be processing one item at a time but didn't take into account that your input list keeps shrinking, so you should decrement your starting index by one each time. Your base case probably should not check that the ending index be 0, you never modify it and you wouldn't call it with 0.
Also your indexOf/3 procedure seems to find any location where the item is found (there may be duplicate items in your list).
You are also misusing the list structure [Head|Tail] (forgot the square brackets).
You may do your slicing by using append/3:
slice(L, From, To, R):-
length(LFrom, From),
length([_|LTo], To),
append(LTo, _, L),
append(LFrom, R, LTo).
In this answer I assumed your index starts at 1.
Sample run:
?- slice([a,b,c,d,e], 1, 4, R).
R = [b, c].
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)
)
).
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).
I'm trying to write a Prolog predicate that can decomposes a given non-negative integer into every possible sum, using a DCG.
For example:
?- s(3, L, []).
L = [3] ? ;
L = [2,1] ? ;
L = [1,2] ? ;
L = [1,1,1] ? ;
false.
I started by writing a predicate which takes a number N and returns L = [1,2,3,...,N]:
mkList(N, L) :-
m(0, N, L).
m(X, X, []).
m(Y, L, [H|T]) :-
H is Y+1,
m(H, L, T).
However, I'm not sure how I can proceed.
s(Input) -->
{ mkList(Input, InputList) },
{ member(X, InputList) },
[X].
This is what I was going to use, it starts out my running through the list one by one. However, I'm not sure where I should include a rule to find the difference between X and Input.
the base case is easy:
all_sum(N) --> [N].
now, we can call recursively if we provide a M between 1 and N, and take the rest R (beware it must be > 0)
all_sum(N) --> {...},[M],all_sum(R).
please fill the dots using the hints above.
You will get
?- phrase(all_sum(3),L).
L = [3] ;
L = [1, 2] ;
L = [1, 1, 1] ;
L = [2, 1] ;
false.
The best way to proceed is to think like Prolog, that is, recursively. Yes, you've got recursion. It may even be right, but I'm not following it.
Thinking like this should work:
mkList(Number,List) :-
pick a number between 1 and number. It'll be your first addend.
subtract it from number to get the remainder.
make a recursive call to handle the remainder.
patch together List based on the first addend and the list from the recursive call.
Obviously we need to stop when Number is less than 1.
This doesn't use a DCG, but for the life of me I can't see how a DCG is relevant here.
This is my first time asking a question here but I have a problem that I really can't wrap my head around which is Prolog recursion especially when it deals with list. So the task that I am supposed to solve is to write a drop predicate that works like this. For example, drop([1,2,3,4,5,6,7,8,9], 2, L) where L = [1,3,5,7,9] and N=n where elements at position n, 2n, 3n.... will be removed. The list starts from 1 is another thing to be noted.
Here is my attempt so far and thought process:
drop([], _, []).
indexOf([X|_], X, 1). %Using 1 because the question says the first element starts from 1.
indexOf([_|Ys], Y , I):-
indexOf(Ys, Y, N),
I is N + 1.
drop([X|Xs], Y, [X|_]) :-
indexOf([X|Xs] , X , A),
Z is A mod Y,
Z \== 0.
drop([X|Xs], Y, Zs) :-
%indexOf([X|Xs], X, A),
drop(Xs, Y, Zs).
I created an indexOf predicate to find the index of the elements starting from 1 . Next, my idea was to use the my first drop recursive case (in the code above it is the 5th case) to check and see whether the position of the element returns a remainder of zero when divided by the Y (second input). if it does not return a remainder of zero, then the X remains inside the list and is not dropped. Then, prolog moves on to the 2nd drop recursive case which can only be arrived when Z=0 and it will drop X from the list to return Zs. In essence, an element with index n, 2n, 3n... that is returned by indexOf will be dropped if it does not return a remainder of zero when divided by Y (second input).
I have not learnt Cut at this point of the course at the moment. I would appreciate if someone can point me to the right direction. I have been working on this for almost a day.
I am still trying to adapt the logic and declarative thinking in this programming paradigm. I would appreciate it if you could share with me, how did you personally go about mastering Logic programming?
First, looking at your approach, there's a flaw with using the indexOf/3. That is, at a given point in time when you need to know the index of what you're removing, you don't know what the item is yet until you get to it. At that point, the index is 1.
That's one issue with the following rule:
drop([X|Xs], Y, [X|_]) :-
indexOf([X|Xs], X, A),
Z is A mod Y,
Z \== 0.
The first subquery: indexOf([X|Xs], X, A) will succeed with A = 1 on its first attempt, just by definition (of course, X has index 1 in list [X|Xs]. As it succeeds, then the next line Z is A mod Y yields 1 since 1 mod Y is always 1 if Y > 0. And therefore, Z \== 0 will always succeed in this case.
Thus, you get the result: [X|_] where X is the first element of the list. So the first solution you get for, say, drop([1,2,3,4], 2, L). is L = [1|_]. Your third drop/3 predicate clause just recurses to the next element in the list, so then it will succeed the second clause the same way, yielding, L = [2|_], and so on...
Starting from the top, here's a way to think about a problem like this.
Auxiliary predicate
I know I want to remove every N-th element, so it helps to have a counter so that every time it gets to N I will ignore that element. This is done with an auxiliary predicate, drop/4 which will also have a recurring counter in addition to the original N:
drop(L, N, R) :-
drop(L, N, 1, R). % Start counter at 1
Base rule
If I drop any element from the empty list, I get the empty list. It doesn't matter what elements I drop. That's expressed as:
drop([], _, _, []).
You have this rule expressed correctly already. The above is the 4-argument version.
Recursive rule 1 - The N-th element
I have list [X|Xs] and X is the N-th element index, then the result is R if I skip X, reset my index counter to 1, and drop the N-th element from Xs:
drop([_|Xs], N, N, R) :- % I don't care what the element is; I drop it
drop(Xs, N, 1, R).
Recursive rule 2 - Other than the N-th element
I have list [X|Xs] and X is the A-th element (< N), then the result is [X|R] if I increment my index counter (A), and drop N-th elements from Xs with my updated index counter:
drop([X|Xs], N, A, [X|R]) :-
A < N,
NextA is A + 1,
drop(Xs, N, NextA, R).
Those are all the needed rules (4 of them).