Increment a variable by constant in recursive rules in prolog - prolog

Here's the line of code written in prolog to make an lcm (Least Common Multiple) rule:
lcm(A, B, A) :-
A > B,
A mod B =:= 0,
!.
lcm(A, B, B) :-
B > A,
B mod A =:= 0,
!.
lcm(A, B, X) :-
A < B,
ImproveB is B + B,
lcm(A, ImproveB, X).
lcm(A, B, X) :-
A > B,
ImproveA is A + A,
lcm(ImproveA, B, X).
I noticed that there's a bug in these lines of code.
For example, the case is lcm(16,10,X) which operated as below:
lcm(16,10,X).
lcm(32,10,X).
lcm(64,10,X).
lcm(128,10,X).
...
It will double the larger number and not increment it by the expected constant. The expected operation is as below:
lcm(16,10,X).
lcm(32,10,X).
lcm(48,10,X).
lcm(64,10,X).
lcm(80,10,X).
since 80 mod 10 is 0, so the result of X is 80
So, how to handle this situation?

To solve the problem, the constant value to be added must be passed as an extra argument (which does not change). Also, to reduce the number of clauses, you can fix the order of the arguments so that the first one is the maximum and the second one is the minimum:
lcm(A, B, C) :-
Min is min(A, B),
Max is max(A ,B),
lcm_loop(Max, Min, Max, C).
lcm_loop(A, B, K, C) :-
( A mod B =:= 0
-> C = A
; A1 is A + K,
lcm_loop(A1, B, K, C) ).

Related

Prolog - Multiplication by recursive addition

I am trying to recursively do addition to multiply two numbers in swi-prolog. I am currently learning Prolog and I do not want to use any library like clpfd.
mult(A, B, C) :- A < B, mult(B, A, C). % always make the first number bigger
mult(A, B, C) :- B > 0, B1 is B - 1, mult(A, B1, A + C). % keep adding
mult(A, B, C) :- B == 0, C is 0. % base case
'C' is supposed to be the result.
This is trying to replicate the following algorithm in Java:
int product(int x, int y)
{
# first prolog line
if (x < y)
return product(y, x);
# second prolog line
else if (y != 0)
return (x + product(x, y - 1));
# third prolog line
else
return 0;
}
However, no matter how I vary the input, the result will always be 'false'. I was able to step through my instructions with :- trace., but I cannot find out how to fix this.
The problem is the last literal of your second clause: mult(A, B1, A + C).
What you really want is the result of A*B1 to add that to A.
So try replacing this line with:
mult(A, B, C) :- B > 0, B1 is B - 1, mult(A, B1, C1), C is A + C1.

Truly Tail-Recursive modInverse() in Prolog

Rosetta code delivers me the following code snippet
for modinv/3. It does calculate extended GCD via egcd/4 and then
derives from it modinv/3:
egcd(_, 0, 1, 0) :- !.
egcd(A, B, X, Y) :-
divmod(A, B, Q, R),
egcd(B, R, S, X),
Y is S - Q*X.
modinv(A, B, N) :-
egcd(A, B, X, Y),
A*X + B*Y =:= 1,
N is X mod B.
Example queries:
?- modinv(42, 2017, N).
N = 1969.
?- modinv(42, 64, X).
false.
There is a slight problem with the solution. It is not
tail recursive. Namely the (is)/2 is the last call of
egcd/4 and not egcd/4 itself.
So the predicate might build-up a stack, a stack that
might contain large big numbers. How would one go about
and realize a more tail recursive solution?
The same site you mention has other algorithms amenable for a tail recursive solution.
Here I translated one from the C++ section (note there is a constraint missing in the original C++ code, it is not checking the last value of A):
modinv(A, B, N):-
modinv(A, B, 1, 0, N1),
(N1 < 0 -> N is N1 + B ; N1 = N).
modinv(A, B, X, Y, N):-
(B=0 -> (A=1, N=X) ;
(
divmod(A, B, Q, R),
Exp is X - Y * Q,
modinv(B, R, Y, Exp, N)
)
).
Sample queries:
?- modinv(42, 2017, N).
N = 1969.
?- modinv(42, 64, X).
false.

Split a list in two halves, reversing the first half using difference lists

I need to do an exercise similar to this:
Prolog - Split a list in two halves, reversing the first half.
I am asked to take a list of letters into two lists that are either equal in size (even sized original list I guess) or one is larger than the other by one element (odd sized list), and reverse the first one while I'm at it, but using only difference lists.
These are the required query and output
?-dividelist2([a,b,c,d,e,f | T] - T, L1-[], L2-[]).
L1 = [c,b,a]
L2 = [d,e,f]
?-dividelist2([a,b,c,d,e | T] - T, L1-[], L2-[]).
L1 = [c,b,a]
L2 = [d,e]
% OR
L1 = [b,a]
L2 = [c,d,e]
This is my code using the previous example but modified, I don't know how to properly compare the two lists
"deduct" them from the input and produce [d,e,f]?
dividelist2(In -[], L1-[], L2-[]) :-
length_dl(In - [],L), % length of the list
FL is L//2, % integer division, so half the length, Out1 will be 1 shorter than Out2 if L is odd
( \+ (FL*2 =:= L), % is odd
FLP is FL + 1 % odd case
; FLP = FL % odd and even case
),
take(In,FLP,FirstHalf),
conc([FirstHalf| L2]-l2,L2-[],In-[]),
reverse1(FirstHalf-[], L1-[]). % do the reverse
reverse1(A- Z,L - L):-
A == Z , !.
reverse1([X|Xs] - Z,L - T):-
reverse1(Xs - Z, L - [X|T]).
length_dl(L- L,0):-!.
length_dl([X|T] - L,N):-
length_dl(T- L,N1),
N is N1 + 1 .
take(Src,N,L) :- findall(E, (nth1(I,Src,E), I =< N), L).
conc(L1-T1,T1-T2,L1-T2).
This is the current trace:
Call:dividelist2([a, b, c, d, e, f|_22100]-_22100, _22116-[], _22112-[])
Call:length_dl([a, b, c, d, e, f]-[], _22514)
Call:length_dl([b, c, d, e, f]-[], _22520)
Call:length_dl([c, d, e, f]-[], _22526)
Call:length_dl([d, e, f]-[], _22532)
Call:length_dl([e, f]-[], _22538)
Call:length_dl([f]-[], _22544)
Call:length_dl([]-[], _22550)
Exit:length_dl([]-[], 0)
Call:_22554 is 0+1
Exit:1 is 0+1
Exit:length_dl([f]-[], 1)
Call:_22560 is 1+1
Exit:2 is 1+1
Exit:length_dl([e, f]-[], 2)
Call:_22566 is 2+1
Exit:3 is 2+1
Exit:length_dl([d, e, f]-[], 3)
Call:_22572 is 3+1
Exit:4 is 3+1
Exit:length_dl([c, d, e, f]-[], 4)
Call:_22578 is 4+1
Exit:5 is 4+1
Exit:length_dl([b, c, d, e, f]-[], 5)
Call:_22584 is 5+1
Exit:6 is 5+1
Exit:length_dl([a, b, c, d, e, f]-[], 6)
Call:_22590 is 6//2
Exit:3 is 6//2
Call:3*2=:=6
Exit:3*2=:=6
Call:_22590=3
Exit:3=3
Call:take([a, b, c, d, e, f], 3, _22594)
Call:'$bags' : findall(_22518, (nth1(_22514, [a, b, c, d, e, f], _22518),_22514=<3), _22614)
Exit:'$bags' : findall(_22518, '251db9a2-f596-4daa-adae-38a38a13842c' : (nth1(_22514, [a, b, c, d, e, f], _22518),_22514=<3), [a, b, c])
Exit:take([a, b, c, d, e, f], 3, [a, b, c])
Call:conc([[a, b, c]|_22112]-l2, _22112-[], [a, b, c, d, e, f]-[])
Fail:conc([[a, b, c]|_22112]-l2, _22112-[], [a, b, c, d, e, f]-[])
Fail:dividelist2([a, b, c, d, e, f|_22100]-_22100, _22116-[], _22112-[])
false
thanks
This is not an answer but testing and debugging suggestions that doesn't fit the comment length limit. The suggestions use Logtalk, which you can run with most Prolog systems.
From your question, the dividelist2/3 predicate needs to satisfy a couple of properties, one of them describing the lengths of the resulting lists. We can express this property easily using a predicate, p/1:
p(DL) :-
difflist::length(DL, N),
dividelist2(DL, DL1, DL2),
difflist::length(DL1, N1),
difflist::length(DL2, N2),
N is N1 + N2,
abs(N1 - N2) =< 1.
Here I'm using Logtalk's difflist library object to compute the length of the difference lists. Given this predicate, we can now perform some property-testing of your dividelist2/3 predicate.
Using Logtalk lgtunit tool implementation of property-testing, we get:
?- lgtunit::quick_check(p(+difference_list(integer))).
* quick check test failure (at test 1 after 0 shrinks):
* p(A-A)
false.
I.e. your code fails for the trivial case of an empty difference list. In the query, we use the difference_list(integer) type simply to simplify the generated counter-examples.
Let's try to fix the failure by adding the following clause to your code:
dividelist2(A-A, B-B, C-C).
Re-trying our test query, we now get:
?- lgtunit::quick_check(p(+difference_list(integer))).
* quick check test failure (at test 2 after 0 shrinks):
* p([0|A]-A)
false.
I.e. the dividelist2/3 predicate fails for a difference list with a single element. You can now use the difference list in the generated counter-example as a starting point for debugging:
?- dividelist2([0|A]-A, L1, L2).
A = [0|A],
L1 = _2540-_2540,
L2 = _2546-_2546 ;
false.
You can also use property-testing with your auxiliary predicates. Take the length_dl/2 predicate. We can compare it with another implementation of a predicate that computes the length of a difference list, e.g. the one in the Logtalk library, by defining another property:
q(DL) :-
difflist::length(DL, N),
length_dl(DL, N).
Testing it we get:
?- lgtunit::quick_check(q(+difference_list(integer))).
* quick check test failure (at test 3 after 0 shrinks):
* q([-113,446,892|A]-A)
false.
Effectively, using the counter.example, we get:
?- length_dl([-113,446,892|A]-A, N).
A = [-113, 446, 892|A],
N = 0.
Hope that this insight helps in fixing your code.
Ok, my idea can work, but seems somewhat inelegant. We'll begin with a handy utility that'll turn a list into a difference list:
list_dl([], W-W).
list_dl([H|T1], [H|T2]-W) :-
list_dl(T1, T2-W).
Now we want a predicate to take the first and last element from the difference list. The case where there's only one element left will need to be handled differently, so we'll make that one unique.
head_last(Head, Head, DL-Hole, one) :-
once(append([Head|_], [Last, Hole], DL)),
var(Last), !.
head_last(Head, Last, DL-Hole, New) :-
once(append([Head|Mid], [Last, Hole], DL)),
list_dl(Mid, New).
Now we can create our recursive split and reverse predicate, which has 3 base cases:
splitrev(W-W, [], []) :- var(W), !. % Empty base case.
splitrev(DL, [V|[]], []) :- head_last(V, V, DL, one).
splitrev(DL, [], [V|[]]) :- head_last(V, V, DL, one).
splitrev(DL, [Head|Front], [Last|Back]) :-
head_last(Head, Last, DL, Rest),
splitrev(Rest, Front, Back).
Unfortunately it's much easier to add an element to the back of a difference list than it is to get an element from the back, plus getting that element closed the hole in the list. Therefore I think a different strategy would be better.

Successor Arithmetic Prolog Mod function

How to write mod/3 function for successor arithmetic (Peano's Numbers) in prolog?
Think of it this way:
If you want to find the mod of 10 and 4, you divide 10 by 4 and return the reminder. But since divide is multiple subtractions we will use the multiple subtraction logic here.
For Example: 10 mod 4 is same as 10-4 mod 4 which is 6 mod 4 which is again same as 6-4 mod 4 = 2 mod 4. Since the first element (2) is less than the second (4), we terminate the program here and return first element (2).
mod(_, 0, 0). Says that anything mod 0 is 0.
mod(0, _ , 0). Says that 0 mod anything is 0.
mod(X, s(0), 0). Says that anything mod 1 is 0.
This is the tricky part:
mod(A, B, N) :- minus(A, B, R), (R #< B -> N = R ; mod(R, B, N)). This uses the multiple minus logic. If first removes second from first and then checks if first is smaller that the second. If yes, recursively call the mod function. If not return the first element.
s(0).
s(X):- X.
plus(0, Y, Y).
plus(s(X), Y, s(Z)):- plus(X , Y , Z).
minus(A, B, C) :- plus(C, B, A).
mod(_, 0, 0).
mod(0, _ , 0).
mod(X, s(0), 0).
mod(A, B, N) :- minus(A, B, R), (R #< B -> N = R ; mod(R, B, N)).
Thank you #Toby for the edit request.

Sequence of Fibonnaci Numbers - Prolog

While attempting to learn Prolog I came across a good exercise which was to write a program that displays the Nth Fibonacci number. After some work I got it working and then decided to see if I could write a program that displays a range of Fibonacci numbers according to the input.
For instance the input:
?- fib_sequence(2,5,Output).
Gives the output:
?- Output = [1,1,2,3]
I am having difficulty, however, in finding a good starting point. This is what I have so far:
fib(0, 0).
fib(1, 1).
fib(N, F) :- X is N - 1, Y is N - 2, fib(X, A), fib(Y, B), F is A + B.
fib_sequence(A,B,R) :- fib(A,Y) , fib(B,Z).
I know I must assign a value to R, but I'm not sure how to assign multiple values. Any help is greatly appreciated.
Observe that your fib_sequence cannot be done in a single predicate clause: you need at least two to keep things recursive - one to produce an empty list when A is greater than B (i.e. we've exhausted the range from A to B), and another one to prepend X from fib(A,X) to a list that you are building, increment A by 1, and call fib_sequence recursively to produce the rest of the sequence.
The first predicate clause would look like this:
fib_sequence(A,B,[]) :- A > B.
The second predicate clause is a bit harder:
fib_sequence(A,B,[H|T]) :-
A =< B /* Make sure A is less than or equal to B */
, fib(A, H) /* Produce the head value from fib(A,...) */
, AA is A + 1 /* Produce A+1 */
, fib_sequence(AA, B, T). /* Produce the rest of the list */
Prolog has some helper builtin to handle numeric sequences, then as an alternative to dasblinkenlight' answer, here is an idiomatic 'query':
fib_sequence(First, Last, Seq) :-
findall(F, (between(First,Last,N), fib(N,F)), Seq).
note that it will not work out-of-the-box with your fib/2, because there is a bug: I've added a condition that avoid the endless loop you would experience trying to backtrack on fib/2 solutions:
fib(N, F) :- N > 1, % added sanity check
X is N - 1, Y is N - 2, fib(X, A), fib(Y, B), F is A + B.
Here's yet another approach. First, I redid fib a little so that it only recursively calls itself once instead of twice. To do this, I created a predicate that returns the prior the last two Fibonacci values instead of the last one:
fib(N, F) :-
fib(N, F, _).
fib(N, F, F1) :-
N > 2,
N1 is N-1,
fib(N1, F1, F0),
F is F0 + F1.
fib(1, 1, 0).
fib(2, 1, 1).
For getting the sequence, I chose an algorithm with the Fibonacci calculation built-in so that it doesn't need to call fib O(n^2) times. It does, however, need to reverse the list when complete:
fib_sequence(A, B, FS) :-
fib_seq_(A, B, FSR),
reverse(FSR, FS).
fib_sequence_(A, B, []) :-
A > B.
fib_sequence_(A, B, [F]) :-
A =:= B,
fib(A, F, _).
fib_sequence_(A, B, [F1,F0]) :-
1 is B - A,
fib(B, F1, F0).
fib_sequence_(A, B, [F2,F1,F0|FT] ) :-
B > A,
B1 is B - 1,
fib_sequence_(A, B1, [F1,F0|FT]),
F2 is F1 + F0.
Here's one more way, to do it without the reverse, but the reverse method above still appears to be a little faster in execution.
fib_sequence_dl(A, B, F) :-
fib_sequence_dl_(A, B, F, [_,_|[]]).
fib_sequence_dl_(A, B, [], _) :-
A > B, !.
fib_sequence_dl_(A, B, [F], _) :-
A =:= B,
fib(A, F, _), !.
fib_sequence_dl_(A, B, [F0,F1|T], [F0,F1|T]) :-
1 is B - A,
fib(B, F1, F0), !.
fib_sequence_dl_(A, B, F, [F1,F2|T]) :-
A < B,
B1 is B - 1,
fib_sequence_dl_(A, B1, F, [F0,F1|[F2|T]]),
F2 is F0 + F1.

Resources