Prolog Break Money into Smaller Amounts - prolog

I have this predicate which returns true if S is equal to some equation say K + 2N + 3L = S. The money we have are 1, 5, and 10 respectively for K, N, L.
I don't want to use :- use_module(library(clpfd)), I want to solve this without it.
My intuition was to break this into subproblems like write a function breakMoney1(S,K) :- K is S. and create more helpers with one more parameter added however I am struggling with the problem of getting uninstantiated variables, when I compare.
breakMoney(S,K,N,L) :-

This is easier than you think, probably. A very naive solution following #Will Ness' suggestion would be:
break(Sum, K, N, L) :- integer(Sum), Sum >= 0,
% upper bounds for K, N, and L
K_Max is Sum div 1,
N_Max is Sum div 5,
L_Max is Sum div 10,
% enumerate possible values for K, N, and L
between(0, L_Max, L),
between(0, N_Max, N),
between(0, K_Max, K),
Sum =:= K + 5*N + 10*L.
This will "magically" turn into a clp(fd) solution with very little effort: for example, replace between with X in 0..Max, and the =:= with #=. Although, it should be enough to simply say that X #>= 0 for each of the denominations. It is a good exercise to see how much of the constraints you can remove and still get an answer:
break(Sum, K, N, L) :-
K #>= 0, N #>= 0, L #>= 0,
Sum #= K + 5*N + 10*L.
Depending on how you instantiate the arguments, you might immediately get a unique answer, or you might need to use label/1:
?- break(100, P, 8, 5).
P = 10.
?- break(10, K, N, L).
K in 0..10,
-1*K+ -5*N+ -10*L#= -10,
N in 0..2,
L in 0..1.
?- break(10, K, N, L), label([K, N, L]).
K = N, N = 0,
L = 1 ;
K = L, L = 0,
N = 2 ;
K = 5,
N = 1,
L = 0 ;
K = 10,
N = L, L = 0.
But as #lurker has pointed out, there is very little reason not to use constraint programming for this problem. Unless, of course, you have a very clever algorithm for solving this particular problem and you know for a fact that it will outsmart the generic clp(fd) solution. Even then, it might be possible to achieve the same effect by using the options to labelling/2.

Related

Prolog query: how does addition matter for recursive queries

I'm trying to write a predicate to find the nth element of a list.
Initially I wrote something like this:
nth([X|_], 0, X).
nth([_|T],N,Z):- N > 0, nth(T, M, Z), N is M + 1.
It works for queries such as nth([1, 2, 3, 4, 5], 0, X). but for queries such as nth([1, 2, 3, 4, 5], N, 1)., I get an "arguments insufficiently instantiated error" after I enter ";" after getting the answer. I know that there will be only 1 ans in this case, but for the sake of completeness, I want to know why.
I read on stack overflow here that the following is a better solution:
nth([X|_], 0, X) :- !.
nth([_|Y], N, Z) :- N > 0, M is N-1, nth(Y, M, Z).
I want to understand why M is N-1, nth(Y, M, Z). makes a difference as against the nth(T, M, Z), N is M + 1 in my answer.
PS: I think the question title can be improved, but I'm not sure of how. If you have suggestions, please let me know!
is/2 is not a complete constraint solver. So N is M + 1 and M is N - 1 look to be equivalent but they are not. The first only succeeds when M is instantiated and second when N is instantiated. Have you tried your solution with indices other zero? They will not work. You can use plus(1, M, N) instead of either of them to get it to work. Also clause ordering matters so plus(1, M, N) should be before the recursive call to nth.
nth([X|_], 0, X).
nth([_|T],N,Z):- N > 0, plus(1, M, N), nth(T, M, Z).
If N > 0, nth(T, M, Z), plus(1, M, N) is your clause ordering, your program will try to satisfy nth(T, M, Z) first and cause an uninstantiated error at N > 0 since M is not already instantiated.
Also neither program will work in the generative case.

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].
?-

Can someone describe this Prolog code step by step?

Prolog is new to me. I'm trying to understand this code. If anyone could explain it step by step in child language that would be a great help ;) thankyou!
divide_by(X,D,I,R) :-
X < D,
I is 0,
R is X.
divide_by(X,D,I,R) :-
X >= D,
Q is X - D,
divide_by(Q, D, S, R),
I is S +1.
Well, I can't. You are asking the wrong question. The right question would be:
What relation does the predicate describe?
Actually, that is quite difficult to answer, as we would have go through it step-by-step. But there is a better and much cleaner way! As your program uses integers only, we can map the moded relations (<)/2, (is)/2 and the like to their declarative counterparts in CLP(FD). So I change < to #<, is to #=, >= to #>=.
:- use_module(library(clpfd)).
divide_by(X,D,I,R):-
X #< D, I #= 0, R #= X.
divide_by(X,D,I,R):-
X #>= D, Q #= X - D,
I #= S +1,
divide_by(Q, D, S, R).
The big advantage now is that I can ask Prolog what it thinks the relation is describing. Simply ask: (Don't worry about the Q=Q, it's just to reorder variables)
N ... dividend
D ... divisor
Q ... quotient
R ... remainder
?- Q=Q, divide_by(N,D,Q,R).
Q = 0, N = R, N#=<D+ -1
This answer reads as follows: The quotient is zero, the dividend and remainder is the same and the remainder is less than the divisor. So this describes all situations where 0 is the "result" or quotient.
Next answer:
; Q = 1, R+D#=N, R#=<D+ -1, N#>=D
The quotient is 1 and the dividend is the divisor plus remainder, and — as in all answers — the remainder is less than the divisor
; Q = 2, _A+D#=N, R+D#=_A, R#=<D+ -1, N#>=D, _A#>=D
This answer is the same as R+D+D#= N. The system has introduced some extra variables. Not wrong, but a bit clumsy to read.
; Q = 3, _A+D#=N, _B+D#=_A, R+D#=_B, R#=<D+ -1, N#>=D, _A#>=D, _B#>=D
; Q = 4, _A+D#=N, _B+D#=_A, _C+D#=_B, R+D#=_C, R#=<D+ -1,
N#>=D, _A#>=D, _B#>=D, _C#>=D
; ... .
And so on. Let me summarize. All answers look like that:
N#>=D, R#< D, R+D+...+D#= N
^^^^^^^ Q times
or even better:
N#>=D, R #< D, R+Q*D #= N, Q #>= 0.
So what we have answered is what this relation is describing.
When you start Prolog, focus on the declarative side. As what (set/relation) a predicate describes. The procedural side will join without any effort later on.
The first rule is called the base case. It will terminate the recursion.
divide_by(X,D,I,R):-
X < D, % this rule apply only if numerically X is < D
I is 0, % will fail if I \= 0
R is X. % if I = 0 assign expression X to R
This other it's the recursive step.
divide_by(X,D, I, R):-
X >= D, % this rule apply only if X is >= D
Q is X - D, % evaluate Q
divide_by(Q, D, S, R), % recursive call. Q & D are surely instantiated
I is S + 1. % evaluate I as S + 1
So, I would say: it will compute the integer division of X by D, with remainder R, when called in mode divide_by(+,+,-,-), that is with first two arguments bound to integers and the last two free.
Anyway, false' answer is very good, as show a possible way to reason about arithmetic that is not available in 'common' programming languages.

Checking circular primes in Prolog

I am new to Prolog and am having a hard time figuring out what is wrong with my code.
I am trying to find circular prime numbers
So far I have this code:
isCircularPrime(N):-
prime(N),
numDigits(N, Y),
Y2 is Y-1,
rotate(N,Y,N2),
circularPrime(N2, Y2, Y2).
circularPrime(_, 0, _).
circularPrime(N, 1, _):-prime(N).
circularPrime(N, I, J):-
I > 1,
prime(N),
I2 is I-1,
rotate(N,J,N2),
circularPrime(N2,I2,J).
Where:
numDigits makes Y the number of digits in N.
rotate makes N2 a rotation of N (e.g. 12 -> 21).
prime is true if N is prime, false otherwise
Currently it recurses infinitely whenever a number is prime but not a circular prime (e.g. 19, 23, etc). If someone could explain what I'm doing wrong, I would really appreciate it.
Here is the other code in case anyone wants to test this for themselves:
prime(2).
prime(3).
prime(N):-
N>3,
N mod 2 =\= 0,
\+ divisible(N,3).
divisible(N,I):- N mod I =:= 0.
divisible(N,I):-
I*I < N,
I2 is I + 2,
divisible(N, I2).
numDigits(N, 1):-
N<10, N>0.
numDigits(N, X):-
N2 is N/10,
numDigits(N2, Y),
X is (Y+1).
rotate(N, L, R):-
LastDigit is N mod 10,
Base is div(N, 10),
Exponent is L - 1,
Num is 10**Exponent,
NewBase is LastDigit*Num,
R is Base + NewBase.
I think the problem is in your numDigits/2 predicate.
It offers all kinds of answers, so the program keeps backtracking again and again:
numDigits(1, X).
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
X = 5 etc...
After adding cuts to numDigits/2 the programs seems to behave correctly:
isCircularPrime(19).
false.

Prolog Find N prime numbers

I have a problem with the recursive function of Prolog. I believe I am not implementing it right and need help.
I need to generate the first N prime numbers and return it in a list. Generating the prime number is not an issue, but rather, generating it in a list is the issue I have.
This is the part of the relevant code:
genList(_, 0, _).
genList(X, N, PrimeList, PrimeList):-
N > 0,
isprime(X),
X1 is X +1,
N1 is N -1,
genList(X1,N1,[X|PrimeList], [X|PrimeList]),!.
genList(X, N, PrimeList, PrimeList):-
N>0,
\+isprime(X),
X1 is X + 1,
genList(X1,N,PrimeList, PrimeList).
This is what I type into the Prolog interpreter:
genList(1,N, [],L).
For the 1st line, how do I make the base case such that when N=0, I stop recursing? Is this correct?
As for the next 2 clauses, I am having difficulty in thinking in terms of logic programming. I definitely feel that this is not logic programming style.
I want to say that when isPrime(X) fails, we continue to the next number without saving anything, but when isPrime(X) is true, then we recurse and continue to the next number, saving X.
How do I do that in Prolog?
First of all, you shouldn't need 4 arguments to your main predicate if you only want two. Here you want the list of the first primes up to N. So an argument for N and an argument for the list should be enough:
primeList(N, L) :-
% eventually in the body a call to a worker predicate with more arguments
Now here, your logic is explained in those terms:
primeList(N, [N|L]) :-
% If we're not at the base case yet
N > 0,
% If N is a prime
isPrime(N),
NewN is N - 1,
% Let's recurse and unifie N as the head of our result list in the head
% of the predicate
primeList(NewN, L).
primeList(N, L) :-
% Same as above but no further unification in the head this time.
N > 0,
% Because N isn't a prime
\+ isPrime(N),
NewN is N - 1,
primeList(NewN, L).
To that you'd have to add the base case
primeList(0, []).
You could rewrite that with cuts as follows:
primeList(0, []) :- !.
primeList(N, [N|L]) :-
isPrime(N),
!,
NewN is N - 1,
primeList(NewN, L).
primeList(N, L) :-
NewN is N - 1,
primeList(NewN, L).
Here's what you meant to write:
genList(N, L) :- genList(2, N, L, []).
genList(X, N, L, Z):- % L-Z is the result: primes list of length N
N > 0 ->
( isprime(X) -> L=[X|T], N1 is N-1 ; L=T, N1 is N ),
X1 is X + 1,
genList(X1,N1,T,Z)
;
L = Z.
The if-then-else construct embodies the cuts. And you're right, it's essentially a functional programming style.
We can introduce a little twist to it, disallowing requests for 0 primes (there's no point to it anyway), so that we also get back the last generated prime:
genList(1, [2], 2) :- !.
genList(N, [2|L], PN) :- N>1, L=[3|_], N2 is N-2, gen_list(N2, L, [PN]).
gen_list(N, L, Z) :- L=[P|_], X is P+2, gen_list(X, N, L, Z).
gen_list(X, N, L, Z) :- % get N more odd primes into L's tail
N > 0 ->
( isprime(X) -> L=[_|T], T=[X|_], N1 is N-1 ; L=T, N1 is N ),
X1 is X + 2,
gen_list(X1,N1,T,Z)
;
L = Z. % primes list's last node
Run it:
?- genList(8,L,P).
L = [2, 3, 5, 7, 11, 13, 17, 19]
P = 19
This also enables us to stop and continue the primes generation from the point where we stopped, instead of starting over from the beginning:
?- L = [3|_], gen_list(8, L, Z), Z=[P10|_], writeln([2|L]),
gen_list(10, Z, Z2), Z2=[P20], writeln(Z).
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29|_G1037]
[29,31,37,41,43,47,53,59,61,67,71]
P10 = 29
P20 = 71

Resources