Finding the k'th occurence of a given element - prolog

I just started in Prolog and have the problem:
(a) Given a list L, an object X, and a positive integer K, it returns
the position of the K-th occurrence of X in L if X appears at least K
times in L otherwise 0.
The goal pos([a,b,c,b],b,2,Z) should succeed with the answer Z = 4.
So far I have:
pos1([],H,K,F).
pos1([H],H,1,F).
pos1([H|T],H,K,F):- NewK is K - 1, pos1(T,H,NewK,F), F is F + 1.
pos1([H|T],X,K,F):- pos1(T,X,K,F).
But I can't figure out why I'm getting:
ERROR: is/2: Arguments are not sufficiently instantiated
Any help would be much appreciated!

Use clpfd!
:- use_module(library(clpfd)).
We define pos/4 based on (#>)/2, (#=)/2, if_/3, dif/3, and (#<)/3:
pos(Xs,E,K,P) :-
K #> 0,
pos_aux(Xs,E,K,1,P).
pos_aux([X|Xs],E,K,P0,P) :-
P0+1 #= P1,
if_(dif(X,E),
pos_aux(Xs,E,K,P1,P),
if_(K #< 2,
P0 = P,
(K0+1 #= K,
pos_aux(Xs,E,K0,P1,P)))).
Sample query as given by the OP:
?- X = b, N = 2, pos([a,b,c,b],X,N,P).
X = b, N = 2, P = 4. % succeeds deterministically
How about the following more general query?
?- pos([a,b,c,b],X,N,P).
X = a, N = 1, P = 1
; X = b, N = 1, P = 2
; X = b, N = 2, P = 4 % (exactly like in above query)
; X = c, N = 1, P = 3
; false.

Let's take a high-level approach to it, trading the efficiency of the resulting code for the ease of development:
pos(L,X,K,P):-
numerate(L,X,LN,1), %// [A1,A2,A3...] -> [A1-1,A2-2,A3-3...], where Ai = X.
( drop1(K,LN,[X-P|_]) -> true ; P=0 ).
Now we just implement the two new predicates. drop1(K,L,L2) drops K-1 elements from L, so we're left with L2:
drop1(K,L2,L2):- K<2, !.
drop1(K,[_|T],L2):- K1 is K-1, drop1(K1,T,L2).
numerate(L,X,LN,I) adds an I-based index to each element of L, but keeps only Xs:
numerate([],_,[],_).
numerate([A|B],X,R,I):- I1 is I+1, ( A=X -> R=[A-I|C] ; R=C ), numerate(B,X,C,I1).
Testing:
5 ?- numerate([1,b,2,b],b,R,1).
R = [b-2, b-4].
6 ?- pos([1,b,2,b],b,2,P).
P = 4.
7 ?- pos([1,b,2,b],b,3,P).
P = 0.

I've corrected your code, without changing the logic, that seems already simple enough.
Just added a 'top level' handler, passing to actual worker pos1/4 and testing if worked, else returning 0 - a debatable way in Prolog, imo is better to allow to fail, I hope you will appreciate how adopting this (see comments) simplified your code...
pos(L,X,K,F):- pos1(L,X,K,F) -> true ; F=0.
% pos1([],H,K,F). useless: let it fail
% pos1([H],H,1,F). useless: already handled immediatly bottom
pos1([H|T],H,K,P):- K==1 -> P=1 ; NewK is K - 1, pos1(T,H,NewK,F), P is F + 1.
pos1([_|T],X,K,P):- pos1(T,X,K,F),P is F+1.
I hope you're allowed to use the if/then/else construct. Anyway, yields
7 ?- pos([a,b,c,b],b,2,Z).
Z = 4.
8 ?- pos([a,b,c,b],b,3,Z).
Z = 0.

Something like this. An outer predicate (this one enforces the specified constraints) that invokes an inner worker predicate:
kth( L , X , K , P ) :-
is_list( L ) , % constraint: L must be a list
nonvar(X) , % constriant: X must be an object
integer(K) , K > 0 % constraint: K must be a positive integer
kth( Ls , X , K , 1 , P ) % invoke the worker predicate with its accumulator seeded to 1
. % easy!
is_list/2 ensures you've got a list:
is_list(X) :- var(X) , !, fail .
is_list([]).
is_list([_|_]).
The predicate that does all the work is this one:
kth( [] , _ , _ , _ , 0 ) . % if we hit the end of the list, P is 0.
kth( [X|Ls] , X , K , K , K ) :- ! . % if we find the Kth desired element, succeed (and cut: we won't find another Kth element)
kth( [_|Ls] , X , K , N , P ) :- % otherwise
N < K , % - if we haven't got to K yet ...
N1 is N+1 , % - increment our accumulator , and
kth(Ls,X,K,N1,P) % - recurse down.
. % easy!
Though the notion of returning 0 instead of failure is Not the Prolog Way, if you ask me.

Related

How to generate all pairs of natural numbers in Prolog?

Problem statement:
I'm trying to generate all pairs of natural numbers in Prolog (SWI-Prolog),
i.e. formally have a function f(X,Y), such that:
after calling f(X,Y) with unbound variables X, Y, for each pair of natural numbers (m, n) there exists an n0 such that after pressing semicolon n0 times, Prolog will return (X,Y)=(m,n).
Failed attempt:
I was hoping to write the function using Cantor's pairing function. In short, it enumerates the pairs as follows: (0,0), (1,0), (0,1), (2,0), (1,1), (0,2), (3,0), (2,1), (1,2), (0,3), (4,0)...
I expressed it as follows:
gen(0,0). % 'root'
gen(M,0) :- gen(0, X), M is X+1. % 'jump to the previous diagonal'
gen(M,N) :- gen(X, Y), M is X-1, N is Y+1, N > 0. % 'a step inside a diagonal'
However because of how Prolog search actually works, this ends up with the 2nd rule repeatedly invoking itself, ad infinitem, eventually crashing due to running out of stack space (the only results it returns before that are (0,0) and (1,0), then it gets stuck, repeatedly failing the 2nd rule on '0 is 0+1').
Do you have any ideas how to make this or any other elegant approach work?
Thank you.
Edit - my solution.
Based on the accepted answer (thanks!), I wrote the following code, working as intended:
range(Min, _, Min).
range(Min, Max, Val) :- NewMin is Min+1, Max >= NewMin, range(NewMin, Max, Val).
natnum(0).
natnum(N) :-
natnum(N0),
N is N0 + 1.
gen(A,B) :-
natnum(N),
range(0, N, B),
A is N - B.
When used:
?- gen(X,Y).
X = 0,
Y = 0 ;
X = 1,
Y = 0 ;
X = 0,
Y = 1 ;
X = 2,
Y = 0 ;
X = 1,
Y = 1 ;
X = 0,
Y = 2 ;
X = 3,
Y = 0
and so on...
I give you a start:
Let us start with a predicate that creates all natural numbers on backtracking, yielding a single such number with each solution:
natnum(0).
natnum(N) :-
N #= N0 + 1,
natnum(N0).
Sample query:
?- natnum(N).
N = 0 ;
N = 1 ;
N = 2 ;
N = 3 ;
etc.
Then, we observe that we can generate such pairs without falling into an infinite loop by restricting the sum of each pair. For example:
pair(A-B) :-
natnum(N),
N #>= A + B,
A #>= 0,
B #>= 0,
label([A,B]).
Sample query:
?- pair(P).
P = 0-0 ;
P = 0-0 ;
P = 0-1 ;
P = 1-0 ;
P = 0-0 ;
P = 0-1 ;
P = 0-2 ;
P = 1-0 ;
P = 1-1 ;
P = 2-0 ;
P = 0-0 ;
P = 0-1 ;
P = 0-2 ;
P = 0-3 ;
P = 1-0 ;
P = 1-1 .
This is obviously not perfect: For example, some pairs are reported redundantly. However, the general idea should be clear: Use a good building-block to keep the generation of pairs in check.

Prolog - Multiples of a Number Below an Upper Limit

I am currently making a program in Prolog that will calculate all of the multiples (including itself) of a number, that do not exceed the value of another number. I was testing with the query below:
?- multiples(4,12,R,0)
This query would list all multiples of 4 that are less than or equal to 12 eg. 4, 8, 12. The R would return the result and 0 is where I was intending to implement a counter that would count up for each multiplication eg. 4*1,4*2,4*3. I am stuck and I am not sure if it would be a better design to simply add the multiples and check if it is below the upper bound or if it can be done with a counter or accumulator.
multiples(N,U,R,Ctr) :-
N =< U,
R is Ctr * N,
R =< U,
increment(Ctr,Ctr2),
multiples(N,U,R,Ctr2).
increment(Num, Num1) :-
Num1 is Num+1.
I believe my program is failing at the recursive step of calling multiples from within itself. I know that recursion needs a base case to allow it to exit, but I am completely stuck here and would appreciate some direction.
The problem with you approach is that there is no basecase: indeed your algorithm will always produce false. It will unify R with N, then do the recursion and that recursion will try to unify R with 2*N which will fail.
Well an idea could be to use an accumulator to which you add the delta each time. Something like:
multiples(N,U,R) :-
multiples(N,N,U,R).
multiples(_,C,U,C) :-
C =< U.
multiples(N,C,U,R) :-
C =< U,
C1 is C+N,
multiples(N,C1,U,R).
So here we call multiples(3,12,R). and it will result in:
?- multiples(4,12,R).
R = 4 ;
R = 8 ;
R = 12 ;
false.
CLP(FD) is very helpful here:
:- use_module(library(clpfd)).
multiple(Multiplicand, Max, Multiple) :-
MaxMultiplier #= Max // Multiplicand,
label([MaxMultiplier]),
Multiplier in 1 .. MaxMultiplier,
Multiple #= Multiplier * Multiplicand,
label([Multiple]).
?- multiple(4, 12, M).
M = 4 ;
M = 8 ;
M = 12.
?-
With CLP(FD) in this case, you can also query with the first argument as a variable:
|?- multiple(N, 12, 8).
N = 8 ;
N = 4 ;
N = 2 ;
N = 1.
Or both the multiplier and result:
?- multiple(N, 4, M).
N = M, M = 3 ;
N = M, M = 4 ;
N = M, M = 2 ;
N = 2,
M = 4 ;
N = M, M = 1 ;
N = 1,
M = 2 ;
N = 1,
M = 3 ;
N = 1,
M = 4.
?-
If you want to collect them in a list, you can use findall/3:
?- findall(Multiple, multiple(4, 12, Multiple), Multiples).
Multiples = [4, 8, 12].
?-

Prolog enumerate and test, will recursion work?

I have to make a predicate which will take 2 numbers N,M and will output "yes" when N,M are positive numbers and there are two numbers A,B such that A+B = M and A*B = N.
EDITED CODE:
For example M = 18, N = 45:
A = 0, B = 18, M = 0+18 (true), N = 0*18 (false) so it has to go next with A = 1 & B = 17 and check again...
numbers(M,N) :-
M>0 ,
N>0 ,
A is 0,
B is M,
numbers(N,M,A,B).
numbers(M,N,A,B) :-
M =:= A+B,
N =:= A*B.
numbers(M,N,A,B) :-
M =:= A+B,
not( N =:= A*B),
A is A+1,
B is B-1,
numbers(M,N,A,B).
I don't know how to enumerate A and B variables. Any help will be appreciated.
just add and multiply and check... see is/2 for arithmetic
edit my advice was a bit simplistic, I totally forgot a hint to easily generate integers ranges in Prolog, using nondeterminism:
numbers(M,N) :-
between(1,M,A),between(1,N,B), M =:= A+B, N =:= A*B, writeln((A,B)).
?- numbers(18,45).
3,15
true ;
15,3
true ;
false.
I look at it as a factoring problem:
%
% are M and N magic?
%
magic(M,N) :-
M > 0 ,
N > 0 ,
factor(N,A,B),
M is A+B
.
%
% factor/3: compute the factors of a positive integer
%
factor(N,F1,F2) :-
N > 0 ,
Limit is floor(sqrt(N)) ,
factor(1,Limit,N,F1,F2)
.
factor(F1,Limit,N,F1,F2) :-
F1 =< Limit ,
F2 is N div F1 ,
0 is N mod F1
.
factor(X,Limit,N,F1,F2) :-
X < Limit ,
X1 is X+1 ,
factor(X1,Limit,N,F1,F2)
.

Prolog - dyck path from origin to (2N,0)

Is called Dyck Path.
It is a plane of x and y axis,
where each step will be only (x+1,y+1) or (x+1,y-1)
and will always stay above x-axis
K should means the peak of the Dyck path.
When K is 2 it should means that the peak is 2 and 3.
to form a legal sequence list of matching the parentheses a = '(', and b = ')' and has length 2N
Eg. [a,a,b,b] and [a,b,a,b] are the legal list for N = 2
[a,b,b,a] and [b,a,b,a] do not satisfies for N = 2
need to define the predicate
listFind(L,K,N) satisfies when L has list of order of 2N, for some k >= K
For example
|?- listFind(L,1,3).
L = [a,b,a,b,a,b] ? ;
L = [a,b,a,a,b,b] ? ;
L = [a,a,b,b,a,b] ? ;
L = [a,a,b,a,b,b] ? ;
L = [a,a,a,b,b,b] ? ;
no
|?- listFind(L,2,3).
L = [a,a,b,b,a,b] ? ;
L = [a,a,b,a,b,b] ? ;
L = [a,a,a,b,b,b] ? ;
no
Thanks in advance.
the role of K is unclear to me. Anyway, here is a snippet satisying your test case:
listFind(L, K, N) :-
N2 is N*2,
length(L, N2),
phrase(dyck, L),
% satisfy condition on K
run_length_encoded(L, RLE),
[X-a|_] = RLE, X >= K.
% DCG for Dyck' language over alphabet `a,b`
dyck --> [] ; [a], dyck, [b], dyck.
run_length_encoded([X|S], C) :-
run_length_encoded(S, X, 1, C).
run_length_encoded([Y|S], X, N, E) :-
( X == Y
-> M is N + 1,
run_length_encoded(S, X, M, E)
; E = [N-X|T],
run_length_encoded(S, Y, 1, T)
).
run_length_encoded([], X, C, [C-X]).
As you can see, the interpretation of K is
the sequence must start with at least K consecutives a

Beginner - add multiples of 3 and 5

I'm trying to find the sum of all positive multiples of 3 and 5 below 1000. After adding the portion that's supposed to remove the multiples of 3 from the sum of the multiples of 5, gprolog will keep spitting out "No" for the query ?- sigma(1000,N).
The problem apparently lies in sigma5, but I can't quite spot it:
sigma(Num, Result) :- sigma3(Num, 3, Result3),
sigma5(Num, 5, Result5),
Result is Result3 + Result5.
sigma3(Num, A, Result) :- A < Num,
Ax is A+3,
sigma3(Num, Ax, ResultX),
Result is ResultX + A.
sigma3(Num, A, Result) :- A >= Num,
Result is 0.
sigma5(Num, A, Result) :- A < Num,
mod3 is A mod 3,
0 \= mod3,
Ax is A+5,
sigma5(Num, Ax, ResultX),
Result is ResultX + A.
sigma5(Num, A, Result) :- A < Num,
mod3 is A mod 3,
0 == mod3,
Ax is A+5,
sigma5(Num, Ax, ResultX),
Result is ResultX.
sigma5(Num, A, Result) :- A >= Num,
Result is 0.
What's the problem with my code?
As integers are involved, consider using finite domain constraints. For example, with SWI-Prolog:
?- use_module(library(clpfd)).
true.
?- findall(N, (N mod 3 #= 0 #\/ N mod 5 #= 0, N in 0..999, indomain(N)), Ns),
sum(Ns, #=, Sum).
Ns = [0, 3, 5, 6, 9, 10, 12, 15, 18|...],
Sum = 233168.
Prolog has never been popular for it's arithmetic capabilities.
This is due to the need to represent 'term constructors' for symbolic processing, without undue evaluation, so when actual arithmetic is required we must explicitly allocate the 'space' (a variable) for the result, instead that 'passing down' an expression. This lead to rather verbose and unpleasant code.
But using some popular extension, like CLP(FD), available in GProlog as well as SWI-Prolog, we get much better results, not readily available in other languages: namely, a closure of the integer domain over the usual arithmetic operations. For instance, from the SWI-Prolog CLP(FD) library, a 'bidirectional' factorial
n_factorial(0, 1).
n_factorial(N, F) :- N #> 0, N1 #= N - 1, F #= N * F1, n_factorial(N1, F1).
?- n_factorial(X, 3628800).
X = 10 .
Anyway, here is a simple minded solution to the original problem, similar to what you attempted, but using an accumulator to compute result. This simple trick allows writing a tail recursive procedure, that turns out in better efficiency.
sigma(Num, Result) :-
sigma(1, Num, 0, Result).
sigma(N, M, Acc, Tot) :-
( N < M, !,
( (0 is N mod 3 ; 0 is N mod 5)
-> Sum is Acc + N
; Sum is Acc
),
N1 is N + 1,
sigma(N1, M, Sum, Tot)
; Tot is Acc
).
Test:
?- sigma(1000, X).
X = 233168 .
mod3 is A mod 3,
(as well all the other occurrences of mod3) should be Mod3 since it is a variable.
with that fix, the program runs correctly (at least for N=1000)
btw here is my solution (using higher-order predicates):
sum(S):-
findall(X,between(1,999,X),L), % create a list with all numbers between 1 and 999
include(div(3),L,L3), % get the numbers of list L which are divisible by 3
include(div(5),L,L5), % get the numbers of list L which are divisible by 5
append(L3,L5,LF), % merge the two lists
list_to_set(LF,SF), % eliminate double elements
sumlist(SF,S). % find the sum of the members of the list
div(N,M):-
0 is M mod N.
it's less efficient of course but the input is too small to make a noticeable difference
This all seems very complicated to me.
sum_of( L , S ) :-
L > 0 ,
sum_of( 0 , L , 0 , S )
.
sum_of( X , X , S , S ) . % if we hit the upper bound, we're done.
sum_of( X , L , T , S ) :- % if not, look at it.
X < L , % - backtracking once we succeeded.
add_mult35( X , T , T1 ) , % - add any multiple of 3 or 5 to the accumulator
X1 is X + 1 , % - next X
sum_of( X1 , L , T1 , S ) % - recurse
.
add_mult35( X , T , T ) :- % no-op if X is
X mod 3 =\= 0 , % - not a multiple of 3, and
X mod 5 =\= 0 , % - not a multiple of 5
!. %
add_mult35( X , T , T1 ) :- % otherwise,
T1 is T + X % increment the accumulator by X
.
This could be even more concise than it is.
Aside from my code probably being extraordinarily horrible (it's actually longer than my C solution, which is quite a feat on it's own),
ANSI C:
int sum_multiples_of_three_and_five( int lower_bound , int upper_bound )
{
int sum = 0 ;
for ( int i = lower_bound ; i <= upper_bound ; ++i )
{
if ( 0 == i % 3 || 0 == i % 5 )
{
sum += i ;
}
}
return sum ;
}

Resources