Multiplying peano integers in swi-prolog - prolog

I am currently on the verge of getting mad trying to solve a simple "multiply peano integers" problem in Prolog.
Basic rules
A peano integer is defined as follows: 0 -> 0; 1 -> s(0); 2 -> s(s(0)) s(s(s(0) -> 3 etc.
The relation is to be defined as follows: multiply(N1,N2,R)
Where
N1 is the first peano integer (i.e. something like s(s(0)))
N2 is the second peano integer (i.e. something like s(s(0)))
R is the resulting new peano integer (like s(s(s(s(0))))
I am aware of the fact that Prolog provides basic arithmetic logic by default, but I am trying to implement basic arithmetic logic using peano integers.
As a multiplication is basically a repeated addition, I think it could look something like this:
Prolog attempts
%Addition
% Adds two peano integers 3+2: add(s(s(s(0))),s(s(0)),X). --> X = s(s(s(s(s(0)))))
add(X,0,X).
add(X,s(Y),s(Z)) :- add(X,Y,Z).
%Loop
%Loop by N
loop(0).
loop(N) :- N>0, NewN is N-1, loop(NewN).
The problem is that I am out of ideas how I can get prolog to run the loop N times based on the coefficient, adding the peano integers and building up the correct result. I'm confident that this is rather easy to achieve and that the resulting code probably won't be longer than a few lines of code. I've been trying to achieve this for hours now and it's starting to make me mad.
Thank you so much for your help, and ... Merry Christmas!
Mike

thanks #false for the hint to this post:
Prolog successor notation yields incomplete result and infinite loop
The referenced PDF doc in this post helps clarifying a number of features regarding peano integers and how to get simple arithmetic to work - pages 11 and 12 are particularly interesing: http://ssdi.di.fct.unl.pt/flcp/foundations/0910/files/class_02.pdf
The code could be set up like this - please note the two approaches for multiplying the integers:
%Basic assumptions
int(0). %0 is an integer
int(s(M)) :- int(M). %the successor of an integer is an integer
%Addition
sum(0,M,M). %the sum of an integer M and 0 is M.
sum(s(N),M,s(K)) :- sum(N,M,K). %The sum of the successor of N and M is the successor of the sum of N and M.
%Product
%Will work for prod(s(s(0)),s(s(0)),X) but not terminate for prod(X,Y,s(s(0)))
prod(0,M,0). %The product of 0 with any integer is 0
prod(s(N),M,P) :-
prod(N,M,K),
sum(K,M,P).%The product of the successor of N and M is the sum of M with the product of M and N. --> (N+1)*M = N*M + M
%Product #2
%Will work in both forward and backward direction, note the order of the calls for sum() and prod2()
prod2(0,_,0). %The product of 0 with any given integer is 0
prod2(s(N), M, P) :- % implements (N+1)*M = M + N*M
sum(M, K, P),
prod2(M,N,K).
Which, when consulting the database will give you something like this:
?- prod(s(s(s(0))),s(s(s(0))),Result).
Result = s(s(s(s(s(s(s(s(s(0))))))))).
?- prod2(s(s(s(0))),s(s(s(0))),Result).
Result = s(s(s(s(s(s(s(s(s(0))))))))).
Please note the different behavior of prod() and prod2() when consulting Prolog in reverse direction - when tracing, please pay attention to the way Prolog binds its variables during the recursive calls:
?- prod(F1,F2,s(s(s(s(0))))).
F1 = s(0),
F2 = s(s(s(s(0)))) ;
F1 = F2, F2 = s(s(0)) ;
ERROR: Out of global stack
?- prod2(F1,F2,s(s(s(s(0))))).
F1 = s(s(s(s(0)))),
F2 = s(0) ;
F1 = F2, F2 = s(s(0)) ;
F1 = s(0),
F2 = s(s(s(s(0)))) ;
false.
I would therefore discourage from the use of prod() as it doesn't reliably terminate in all thinkable scenarios and use prod2() instead.
I'm really excited by the people here at StackOverflow. I got so much useful feedback, which really helped me in getting a deeper understanding of how Prolog works. Thanks a ton everyone!
Mike
Edit: Had another look at this issue thanks to #false and the following post: Prolog successor notation yields incomplete result and infinite loop

Related

Prolog recursive subtraction

I picked up prolog a couple of days ago and I 'm kind of stuck to this question. I want to subtract a number recursively until that number becomes less than 0. In pseudocode that would be like:
N:=0
while(Y>=X)
{
Y := Y-X
N := N+1
Y := Y+2
}
So for example if I have Y=20 and X=10 then we would get N=2 and Y=4.
Any ideas? Thanks in advance. Any help appreciated. I'm using SWI Prolog.
EDIT 1
What I've accomplished so far is(although I'm not sure even if its correct):
sufficient(X, Y, M, N, F) :-
F is Y-X,
Y>=X,
plus(M, 1, N),
sufficient(X, F, N, N, F).
I have problem finding my base case, I'm confused on how to implement it. Also, in the sufficient I have implemented, obviously when Y<X it terminates returning false. Is there a way to get the N and F before terminating? I am feeling that I am not thinking the "prolog" way, since I am mostly used on C and that vagues my thinking. Thanks.
EDIT 2
I have found my base case and I can stop recursion however, I can't manage to ge the correct values. My code:
sufficient(X, Y, M, N, F) :- Y<X.
sufficient(X, Y, M, N, F) :-
F is Y-X,
plus(M, 1, N),
sufficient(X, F, N, D, E).
Thing is after the first recursion, if for example I call sufficient as sufficient(10,21,0,N,F). from the swi prolog command prompt, I 'll get N=1 and F=11. That happens because I make 2 new variables D and E. If I don't make those 2 new variables(D and E), and at the 3rd sufficient in the code I call N and F instead of D and E at the line F is Y-X, I get a false, because F is 11 and Y-X is 1. Do I have to set the a subtraction function myself, since F is Y-X is not exactly a subtraction? Any ideas on how to do it?
All recursive functions need at least one base case. In what circumstance should your function say, OK, I have the answer, no need to recurse?
It would be the case in which your pseudocode loop is done, right?
Usually we write it in this format:
factorial(0,1). % The factorial of 0 is 1.
factorial(N,Factorial) :-
N>0, % You may need to test applicability
% of this recursive clause
NMinus1 is N-1, % maybe some setup
factorial(NMinus1,FactorialOfNMinus1), %recursive call
Factorial is N*FactorialOfNMinus1). %and maybe some code after
I wouldn't want to do your homework for you, but this should get you going:
sufficient(X,Y,M,N,F) :- %whatever condition means you're done,
% and results = whatever they should
sufficient(X,Y,M,N,F) :- %whatever condition means you aren't done
% and setting up results w/ a recursive call
One more hint: looks like M is a temporary variable and need not be a parameter.

Prolog program to get an (integer) number as the sum of two integer squares, why does it not work?

I'm starting learning Prolog and I want a program that given a integer P gives to integers A and B such that P = A² + B². If there aren't values of A and B that satisfy this equation, false should be returned
For example: if P = 5, it should give A = 1 and B = 2 (or A = 2 and B = 1) because 1² + 2² = 5.
I was thinking this should work:
giveSum(P, A, B) :- integer(A), integer(B), integer(P), P is A*A + B*B.
with the query:
giveSum(5, A, B).
However, it does not. What should I do? I'm very new to Prolog so I'm still making lot of mistakes.
Thanks in advance!
integer/1 is a non-monotonic predicate. It is not a relation that allows the reasoning you expect to apply in this case. To exemplify this:
?- integer(I).
false.
No integer exists, yes? Colour me surprised, to say the least!
Instead of such non-relational constructs, use your Prolog system's CLP(FD) constraints to reason about integers.
For example:
?- 5 #= A*A + B*B.
A in -2..-1\/1..2,
A^2#=_G1025,
_G1025 in 1..4,
_G1025+_G1052#=5,
_G1052 in 1..4,
B^2#=_G406,
B in -2..-1\/1..2
And for concrete solutions:
?- 5 #= A*A + B*B, label([A,B]).
A = -2,
B = -1 ;
A = -2,
B = 1 ;
A = -1,
B = -2 ;
etc.
CLP(FD) constraints are completely pure relations that can be used in the way you expect. See clpfd for more information.
Other things I noticed:
use_underscores_for_readability_as_is_the_convention_in_prolog instead ofMixingTheCasesToMakePredicatesHardToRead.
use declarative names, avoid imperatives. For example, why call it give_sum? This predicate also makes perfect sense if the sum is already given. So, what about sum_of_squares/3, for example?
For efficiency sake, Prolog implementers have choosen - many,many years ago - some compromise. Now, there are chances your Prolog implements advanced integer arithmetic, like CLP(FD) does. If this is the case, mat' answer is perfect. But some Prologs (maybe a naive ISO Prolog compliant processor), could complain about missing label/1, and (#=)/2. So, a traditional Prolog solution: the technique is called generate and test:
giveSum(P, A, B) :-
( integer(P) -> between(1,P,A), between(1,P,B) ; integer(A),integer(B) ),
P is A*A + B*B.
between/3 it's not an ISO builtin, but it's rather easier than (#=)/2 and label/1 to write :)
Anyway, please follow mat' advice and avoid 'imperative' naming. Often a description of the relation is better, because Prolog it's just that: a relational language.

Quadratic equation solving in Prolog

I have wrote a code to solve equation with like terms (eg:- x^2+5*x+6=0). Here 'x' has two values. I can take two values by entering ';'. But I need to get the all possible answers when I run the program at once. Is it possible in prolog?
Well for a quadratic equation, if the discriminant is zero, then
there is only one solution, so you can directly compute one or two
solutions, and return them in a list.
The discriminat is the expression under the square root. So the
classical prolog code for a real number solution reads as follows:
solve(A*_^2+B*_+C=0,L) :- D is B^2-4*A*C,
(D < 0 -> L = [];
D =:= 0 -> X is (-B)/(2*A), L = [X];
S is sqrt(D), X1 is (-B-S)/(2*A),
X2 is (-B+S)/(2*A), L=[X1,X2]).
Here is an example run:
Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.0)
?- solve(1*x^2+5*x+6=0,L).
L = [-3.0, -2.0].

Prolog: McCarthy 91

I'm learning about recursion and came across the McCarthy 91 function.
I've been able to find examples of it in several languages (C++, Java, Python, Scheme, and so on). I'm trying to find out how it would be written in Prolog though.
I can't find any examples online nor do I have much of an idea about how to write it myself (in Prolog). Could someone post a code example of it or point me towards the proper source online? Thanks greatly for the help.
here is a test in SWI-Prolog, using lifter (I left the non lifted clause commented above, to make easier understanding it).
:- [lifter].
%m(N, M) :- N > 100 -> M is N-10 ; T1 is N+11, m(T1, T2), m(T2, M).
m(N, M) :- N > 100 -> M is N-10 ; m(m(° is N+11, °), M).
and here is the translation in plain Prolog (of course identical to Sergey one, after renaming variables)
6 ?- listing(m).
m(A, B) :-
( A>100
-> B is A-10
; C is A+11,
m(C, D),
m(D, B)
).
true.
7 ?- writeln(m(88,°)).
91
true.
m91(N, M) :-
( N > 100 ->
M is N - 10
;
Np11 is N + 11,
m91(Np11, M1),
m91(M1, M)
).
It's not really a function, but a predicate. Result is "returned" in the second argument:
?- m91(99, M).
M = 91.
?- m91(87, M).
M = 91.
?- m91(187, M).
M = 177.
Some Prolog implementations allow to use predicates like this as arithmetic functions. Using ECLiPSe:
[eclipse]: M is m91(99).
M = 91
Yes (0.00s cpu)
There are several remarkable aspects here. After all, the original intention of this function was to consider it in the context of formal verification.
As long as you encode this function with (is)/2 you will get essentially the same as in other languages - a function where you need to reason about. You need to switch from the moded arithmetic of (is)/2 to the (rudimentary) algebra provided by library(clpfd) to turn Prolog to reason about the relation directly:
:- use_module(library(clpfd)).
m(N0,N):-
N0#>100,
N #= N0-10.
m(N0,N):-
N0#=<100,
N1 #=N0+11,
m(N1,N2),
m(N2,N).
Now, we can not only ask for a concrete result, we can also ask:
?- m(N0,N).
N0 in 101..sup, N+10#=N0, N in 91..sup
; N0 = 100, N = 91
; N0 = 99, N = 91
; N0 = 98, N = 91
; N0 = 97, N = 91
; ... .
Or, more specifically, we might ask when this "function" will be not equal 91:
?- N#\=91, m(N0,N).
N in 92..sup, N+10#=N0, N0 in 102..sup
; loops.
The first answer tells us that for values N0 in 102..sup the result will not be 91. Then, the system tries to find the next answer, but needs too much time (that is, too much time for us finite beings).
Ideally, we would have implemented m/2 like so:
m2(N0,N) :-
N0#>100,
N #= N0-10.
m2(N0,N):-
N0#=<100,
N #= 91.
and in fact, this would be a challenge to a program transformation systems. m2/2 permits Prolog to describe the entire relation with two answers:
?- m2(N0,N).
N0 in 101..sup, N+10#=N0, N in 91..sup
; N = 91, N0 in inf..100.
So we have described here infinitely many solutions with finite means!

Combining two numbers in prolog

Kindly, could you help me in the following:
I am writing a Prolog program that takes two numbers digits then combine them as one number, for example:
Num1: 5
Num2: 1
Then the new number is 51.
Assume V1 is the first number digit and V2 is the second number digit. I want to combine V1 and V2 then multiply the new number with V3, so my question is how I can do it?
calculateR(R, E, V1, V2, V3, V4):-
R is V1 V2 * V3,
E is R * V4.
Your help is appreciated.
Here is another solution that is based on the idea of #aBathologist and that relies on ISO predicates only, and does not dependent on SWI's idiosyncratic modifications and extensions. Nor does it have most probably unwanted solutions like calculateR('0x1',1,1,17). nor calculateR(1.0e+30,0,1,1.0e+300). Nor does it create unnecessary temporary atoms.
So the idea is to restrict the definition to decimal numbers:
digit_digit_number(D1, D2, N) :-
number_chars(D1, [Ch1]),
number_chars(D2, [Ch2]),
number_chars(N, [Ch1,Ch2]).
Here is a version which better clarifies the relational nature of Prolog - using library(clpfd) which is available in many Prolog systems (SICStus, SWI, B, GNU, YAP). It is essentially the same program as the one with (is)/2 except that I added further redundant constraints that permit the system to ensure termination in more general cases, too:
:- use_module(library(clpfd)).
digits_radix_number(Ds, R, N) :-
digits_radix_numberd(Ds, R, 0,N).
digits_radix_numberd([], _, N,N).
digits_radix_numberd([D|Ds], R, N0,N) :-
D #>= 0, D #< R,
R #> 0,
N0 #=< N,
N1 #= D+N0*R,
digits_radix_numberd(Ds, R, N1,N).
Here are some uses:
?- digits_radix_number([1,4,2],10,N).
N = 142.
?- digits_radix_number([1,4,2],R,142).
R = 10.
?- digits_radix_number([1,4,2],R,N).
R in 5..sup, 4+R#=_A, _A*R#=_B, _A in 9..sup, N#>=_A,
N in 47..sup, 2+_B#=N, _B in 45..sup.
That last query asks for all possible radices that represent [1,4,2] as a number. As you can see, not anything can be represented that way. The radix has to be 5 or larger which is not surprising given the digit 4, and the number itself has to be at least 47.
Let's say we want to get a value between 1450..1500, what radix do we need to do that?
?- digits_radix_number([1,4,2],R,N), N in 1450..1500.
R in 33..40, 4+R#=_A, _A*R#=_B, _A in 37..44,
N in 1450..1500, 2+_B#=N, _B in 1448..1498.
Gnah, again gibberish. This answer contains many extra equations that have to hold. Prolog essentially says: Oh yes, there is a solution, provided all this fine print is true. Do the math yourself!
But let's face it: It is better if Prolog gives such hard-to-swallow answer than if it would say Yes.
Fortunately there are ways to remove such extra conditions. One of the simplest is called "labeling", where Prolog will "try out" value after value:
?- digits_radix_number([1,4,2],R,N), N in 1450..1500, labeling([],[N]).
false.
That is clear response now! There is no solution. All these extra conditions where essentially false, like all that fine print in your insurance policy...
Here's another question: Given the radix and the value, what are the required digits?
?- digits_radix_number(D,10,142).
D = [1,4,2]
; D = [0,1,4,2]
; D = [0,0,1,4,2]
; D = [0,0,0,1,4,2]
; D = [0,0,0,0,1,4,2]
; ... .
So that query can never terminate, because 00142 is the same number as 142. Just as 007 is agent number 7.
Here is a straight-forward solution that should work in any Prolog close to ISO:
digits_radix_to_number(Ds, R, N) :-
digits_radix_to_number(Ds, R, 0,N).
digits_radix_to_number([], _, N,N).
digits_radix_to_number([D|Ds], R, N0,N) :-
N1 is D+N0*R,
digits_radix_to_number(Ds, R, N1,N).
?- digits_radix_to_number([1,4,2],10,R).
R = 142.
Edit: In a comment, #false pointed out that this answer is SWI-Prolog specific.
You can achieve your desired goal by treating the numerals as atoms and concatenating them, and then converting the resultant atom into a number.
I'll use atom_concat/3 to combine the two numerals. In this predicate, the third argument with be the combination of atoms in its first and second arguments. E.g.,
?- atom_concat(blingo, dingo, X).
X = blingodingo.
Note that, when you do this with two numerals, the result is an atom not a number. This is indicated by the single quotes enclosing the the result:
?- atom_concat(5, 1, X).
X = '51'.
But 51 \= '51' and we cannot multiply an atom by number. We can use atom_number/2 to convert this atom into a number:
?- atom_number('51', X).
X = 51.
That's all there is to it! Your predicate might look like this:
calculateR(No1, No2, Multiplier, Result) :-
atom_concat(No1, No2, NewNoAtom),
atom_number(NewNoAtom, NewNo),
Result is NewNo * Multiplier.
Usage example:
?- calculateR(5, 1, 3, X).
X = 153.
Of course, you'll need more if you want to prompt the user for input.
I expect #Wouter Beek's answer is more efficient, since it doesn't rely on converting the numbers to and from atoms, but just uses the assumption that each numeral is a single digit to determine the resulting number based on their position. E.g., if 5 is in the 10s place and 1 is in the 1s place, then the combination of 5 and 1 will be 5 * 10 + 1 * 1. The answer I suggest here will work with multiple digit numerals, e.g., in calculateR(12, 345, 3, Result), Result is 1234 * 3. Depending on what you're after this may or may not be a desired result.
If you know the radix of the numbers involved (and the radix is the same for all the numbers involved), then you can use the reverse index of the individual numbers in order to calculate their positional summation.
:- use_module(library(aggregate)).
:- use_module(library(lists)).
digits_to_number(Numbers1, Radix, PositionalSummation):-
reverse(Numbers1, Numbers2),
aggregate_all(
sum(PartOfNumber),
(
nth0(Position, Numbers2, Number),
PartOfNumber is Number * Radix ^ Position
),
PositionalSummation
).
Examples of use:
?- digits_to_number([5,1], 10, N).
N = 51.
?- digits_to_number([5,1], 16, N).
N = 81.
(The code sample is mainly intended to bring the idea across. Notice that I use aggregate_all/3 from SWI-Prolog here. The same could be achieved by using ISO predicates exclusively.)

Resources