How to implement Peano numbers exponentiation in Prolog? - prolog

I am trying to implement exponentiation with the code below, but a simple query like 2^1 (ex(s(s(0)), s(0), Z).) hangs forever.
nat(0).
nat(s(X)) :- nat(X).
su(0, X, X) :- nat(X).
su(s(X), Y, s(Z)) :- su(X, Y, Z).
mu(0, _, 0).
mu(s(X), Y, Z) :- su(Y, A, Z), mu(X, Y, A).
ex(_, 0, s(0)).
ex(X, s(Y), Z) :- mu(X, A, Z), ex(X, Y, A).

As far as I can see, it is not efficient, because the mu/3 is called with two free variables. Indeed:
ex(X, s(Y), Z) :- mu(X, A, Z), ex(X, Y, A).
Both A and Z are unknown at that moment (I have put them in boldface).
Now your mu/2 is not capable of handling this properly. If we query mu/3 with mu(s(0), A, Z), we get:
?- mu(s(0), A, Z).
A = Z, Z = 0 ;
ERROR: Out of global stack
So it got stuck in infinite recursion as well.
This is due to the fact that it will tak the second clause of mu/3, and:
mu(s(X), Y, Z) :- su(Y, A, Z), mu(X, Y, A).
So su/3 is called with three unknown variables. The effect of this is that su/3 can keep proposing values "until the end of times":
?- su(A, B, C).
A = B, B = C, C = 0 ;
A = 0,
B = C, C = s(0) ;
A = 0,
B = C, C = s(s(0)) ;
A = 0,
...
even if the recursive mu(X, Y, A) rejects all these proposals, su/3 will never stop proposing new solutions.
Therefore it might be better to keep that in mind when we design the predicates for mu/3, and ex/3.
We can for example use an accumulator here that accumulates the values, and returns the end product. The advantage of this, is that we work with real values when we make the su/3 call, like:
mu(A, B, C) :-
mu(A, B, 0, C).
mu(0, _, 0, S, S).
mu(s(X), Y, I, Z) :-
su(Y, I, J),
mu(X, Y, J, Z).
Now if we enter mu/3 with only the first parameter fixed, we see:
?- mu(s(0), X, Y).
X = Y, Y = 0 ;
X = Y, Y = s(0) ;
X = Y, Y = s(s(0)) ;
X = Y, Y = s(s(s(0))) ;
...
?- mu(s(s(0)), X, Y).
X = Y, Y = 0 ;
X = s(0),
Y = s(s(0)) ;
X = s(s(0)),
Y = s(s(s(s(0)))) ;
X = s(s(s(0))),
Y = s(s(s(s(s(s(0)))))) ;
...
...
So that means that we now at least do not get stuck in a loop for mu/3 with only the first parameter fixed.
We can use the same strategy to define an ex/3 predicate:
ex(X, Y, Z) :-
ex(X, Y, s(0), Z).
ex(X, 0, Z, Z).
ex(X, s(Y), I, Z) :-
mu(X, I, J),
ex(X, Y, J, Z).
We then manage to calculate exponents like 21 and 22:
?- ex(s(s(0)), s(0), Z).
Z = s(s(0)) ;
false.
?- ex(s(s(0)), s(s(0)), Z).
Z = s(s(s(s(0)))) ;
false.
Note that the above has still some flaws, for example calculating for which powers the value is 4 will still loop:
?- ex(X, Y, s(s(s(s(0))))).
ERROR: Out of global stack
By rewriting the predicates, we can avoid that as well. But I leave that as an exercise.

Related

Prolog program to enumerate all possible solution over a countable set

I am writing a prolog program with can perform Peano arithmetics.
I have standard definitions for natural numbers.
nat(n).
nat(s(N)) :-
nat(N).
Because I want to enumerate all possible relation of addition between natural numbers, I defined an auxiliary function (in order for defining total ordering over the set).
cmp_n(X, Y, lt) :-
nat(Y), % generate a stream : n s(n) s(s(n)) ...
cmp_n_lt_helper(X, Y). % gives all XS smaller than Y
cmp_n_lt_helper(s(X), s(Y)) :-
cmp_n_lt_helper(X, Y).
cmp_n_lt_helper(n, s(Y)) :-
nat(Y).
Then, I defined addition
% need to use a wrapper because I want to generate (n, n, n) first
% if I don't use this warper, it would start from (n, s(n), s(n))
add_n(X, Y, R) :-
nat(R), % same reason as above
cmp_n(X, R, lt),
add_n_helper(X, Y, R).
add_n_helper(s(X), Y, s(R)):-
add_n_helper(X, Y, R).
add_n_helper(n, Y, Y).
If I enumerate all possible relations over this definition of addition, it worked fine. And when outputting a finite set of answers, it can halt.
?- add_n(X, Y, R).
X = Y, Y = R, R = n ;
X = R, R = s(n),
Y = n ;
X = n,
Y = R, R = s(n) ;
X = R, R = s(s(n)),
Y = n ;
X = Y, Y = s(n),
R = s(s(n)) ;
X = n,
Y = R, R = s(s(n)) .
?- add_n(X, Y, s(s(s(s(n))))).
X = s(s(s(s(n)))),
Y = n ;
X = s(s(s(n))),
Y = s(n) ;
X = Y, Y = s(s(n)) ;
X = s(n),
Y = s(s(s(n))) ;
X = n,
Y = s(s(s(s(n)))) ;
false.
These worked fine.
However, if I do the regular forward evaluation,
?- add_n(s(s(s(n))), s(s(n)), R).
R = s(s(s(s(s(n)))))
this program cannot halt.
I am wondering : is there a way to
for any finite answer, give a finite result.
for any infinite answer, fix a specific valid answer, give this specified answer in finite time
As spot properly in the comments and by you as well, you've got a problem in a specific case, when X and Y are defined and R is not.
So let's just solve this case separately without the R generator in that case.
In my implementation (similar to yours)
nat(n).
nat(s(N)) :-
nat(N).
eq_n(n, n) :- !.
eq_n(s(X), s(Y)) :-
eq_n(X, Y), !.
leq_n(n, n).
leq_n(n, Y) :-
nat(Y).
leq_n(s(X), s(Y)) :-
leq_n(X, Y).
movel_n(X, n, X) :- !.
movel_n(X, s(Y), Z) :-
movel_n(s(X), Y, Z), !.
add_n(X, Y, R) :-
( ( var(X)
; var(Y)
),
nat(R),
leq_n(X, R),
leq_n(Y, R)
; \+ var(X),
\+ var(Y), !
),
movel_n(X, Y, Xn),
eq_n(Xn, R).
The most important part for you is the first big or statement of add_n/3.
We're checking there with the var/1 if the variables are instantiated.
If not, we're creating the variables generator,
otherwise, we're just going forward to calculations.

How to implement the factorial sequence in successor arithmetics for all argument modes?

The following Prolog program defines a predicate fact/2 for computing the factorial of an integer in successor arithmetics:
fact(0, s(0)).
fact(s(X), Y) :-
fact(X, Z),
prod(s(X), Z, Y).
prod(0, _, 0).
prod(s(U), V, W) :-
sum(V, X, W),
prod(V, U, X).
sum(0, Y, Y).
sum(s(X), Y, s(Z)) :-
sum(X, Y, Z).
It works with queries in this argument mode:
?- fact(s(0), s(0)).
true
; false.
It also works with queries in this argument mode:
?- fact(s(0), Y).
Y = s(0)
; false.
It also works with queries in this argument mode:
?- fact(X, Y).
X = 0, Y = s(0)
; X = Y, Y = s(0)
; X = Y, Y = s(s(0))
; X = s(s(s(0))), Y = s(s(s(s(s(s(0))))))
; …
But it exhausts resources with queries in this argument mode:
?- fact(X, s(0)).
X = 0
; X = s(0)
;
Stack limit (0.2Gb) exceeded
Stack sizes: local: 4Kb, global: 0.2Gb, trail: 0Kb
Stack depth: 2,503,730, last-call: 100%, Choice points: 13
In:
[2,503,730] sum('<garbage_collected>', _1328, _1330)
[38] prod('<garbage_collected>', <compound s/1>, '<garbage_collected>')
[33] fact('<garbage_collected>', <compound s/1>)
[32] fact('<garbage_collected>', <compound s/1>)
[31] swish_trace:swish_call('<garbage_collected>')
How to implement the factorial sequence in successor arithmetics for all argument modes?
The first question must be why? A failure-slice helps to understand the problem:
fact(0, s(0)) :- false.
fact(s(X), Y) :- fact(X, Z), false, prod(s(X), Z, Y).
This fragment alone terminates only if the first argument is given. If it is not, then there is no way to prevent non-termination, as Y is not restricted in any way in the visible part. So we have to change that part. A simple way is to observe that the second argument continually increases. In fact it grows quite fast, but for the sake of termination, one is enough:
fact2(N, F) :-
fact2(N, F, F).
fact2(0, s(0), _).
fact2(s(X), Y, s(B)) :- fact2(X, Z, B), prod(s(X), Z, Y).
And, should I add, this can be even proved.
fact2(A,B)terminates_if b(A);b(B).
% optimal. loops found: [fact2(s(_),s(_))]. NTI took 0ms,73i,73i
But, there is a caveat...
If only F is known, the program will now require temporally space proprotional to |F|! That is not an exclamation point but a factorial sign...
I think you can use cut to avoid backtracking when the second argument is a ground term.
fact(0, s(0)).
fact(s(X), Y) :-
fact(X, Z),
prod(s(X), Z, W),
(ground(Y) ->
!,
Y = W
; Y = W).
prod(0, _, 0).
prod(s(U), V, W) :- sum(V, X, W), prod(V, U, X).
sum(0, Y, Y).
sum(s(X), Y, s(Z)) :- sum(X, Y, Z).
Examples:
?- fact(N, 0).
false.
?- fact(N, s(s(s(0)))).
false.
?- fact(X, s(0)).
X = 0
; X = s(0)
; false.
?- fact(s(s(s(0))), s(s(s(s(s(s(0))))))).
true
; false.
?- fact(s(s(s(0))), s(s(s(s(s(0)))))).
; false.
?- fact(s(s(s(0))), Y).
Y = s(s(s(s(s(s(0))))))
; false.
?- fact(X, Y).
X = 0, Y = s(0)
; X = Y, Y = s(0)
; X = Y, Y = s(s(0))
; …
?- fact(s(s(X)), s(s(Y))).
X = Y, Y = 0
; X = s(0), Y = s(s(s(s(0))))
; …

How do I change position of two elements in a list(PROLOG)

predicate change_pos(E1, E2,Lin,Lout).
The Lin has any number of elements, and I need to change all occurences of E1 to E2, and vice-versa. And return in Lout.
I was thinking to do something like this:
change(X, Y, [], []).
change(X, Y, [X|L], [Y,L1]):- change(X,Y,L,L1).
change(X, Y, [Z|L], [Z,L1]:- X \== Z, change(X,Y,L,L1).
But this way is not swiping two number of the list
I'm supposing, since this is homework, it's an exercise to learn list processing and recursion. But in Prolog, a common tool for processing each term in turn in a list is maplist:
% Rule for changing one element
change_element(X, Y, X, Y).
change_element(X, Y, Y, X).
change_element(X, Y, Z, Z) :- dif(X, Z), dif(Y, Z).
% Rule for changing a list
change(X, Y, L1, L2) :-
maplist(change_element(X, Y), L1, L2).
Which yields:
?- change(a, b, [a,b,c,b,a], L).
L = [b, a, c, a, b] ? ;
no
?-
For a determinate solution, you can use if_/3:
change1(X, Y, A, B) :-
if_(=(Y, A), B = X, A = B).
change2(X, Y, A, B) :-
if_(=(X, A), B = Y, change1(X, Y, A, B)).
change(X, Y, L1, L2) :- maplist(change2(X, Y), L1, L2).
Which yields:
?- change(a, b, [a,b,c,b,a], L).
L = [b, a, c, a, b].
?-
You're almost there. Your base case (the empty lists) and your second rule (swap X for Y) are basically fine (apart from the details pointed out in the comments). However, you are missing a rule for vice-versa (swap Y for X). And in your last rule you likely want to make sure that Z differs not only from X but also from Y, otherwise Z would be subject to rule two or three.
change(X, Y, [], []).
change(X, Y, [X|L], [Y|L1]) :-
change(X,Y,L,L1).
change(X, Y, [Y|L], [X|L1]) :- % <- vice versa case
change(X,Y,L,L1).
change(X, Y, [Z|L], [Z|L1]) :-
dif(X,Z), % <- neither X=Z
dif(Y,Z), % <- nor vice versa
change(X,Y,L,L1).
Here are some example queries. What does [1,2,3,4] look like after swapping 1 with 2 and vice versa?
?- change(1,2,[1,2,3,4],L).
L = [2,1,3,4] ? ;
no
What did [2,1,3,4] look like before swapping 1 with 2 and vice versa?
?- change(1,2,L,[2,1,3,4]).
L = [1,2,3,4] ? ;
no
Which elements have been swapped in [1,2,3,4] if the resulting list is [2,1,3,4] ?
?- change(X,Y,[1,2,3,4],[2,1,3,4]).
X = 1,
Y = 2 ? ;
X = 2,
Y = 1 ? ;
no

Prolog counting using s(0) and p(0)

I am having some issues with a part of my revision for my prolog exam.
I need to create a recursive statement that will be called simplify/2. An example use would be
simplify(s(p(s(0))),Z)
which would result in Z being s(0). S stands for successor and P predecessor.
So:
s(0) is 1,
s(s(0)) is 2 and p(0) is -1 etc.
and
p(s(p(p(0)))) would be p(p(0)).
The code I initially had was
check(s(0),s(0)).
check(s(X),s(0)) :- check(X,s(s(0))).
check(p(X),s(0)) :- check(X,0).
But this clearly doesn't work as the second part needs to be kept as a variable that is added on to itself during the recursive call. I'll have another look at it in around 30 minutes because my head is fried at the moment.
My attempt:
simplify(X, Z) :-
simplify(X, 0, Z).
simplify(0, Z, Z).
simplify(s(X), 0, Z) :- simplify(X, s(0), Z).
simplify(p(X), 0, Z) :- simplify(X, p(0), Z).
simplify(p(X), s(Y), Z) :- simplify(X, Y, Z).
simplify(s(X), p(Y), Z) :- simplify(X, Y, Z).
simplify(s(X), s(Y), Z) :- simplify(X, s(s(Y)), Z).
simplify(p(X), p(Y), Z) :- simplify(X, p(p(Y)), Z).
Update - shorter version:
simplify(X, Z) :-
simplify(X, 0, Z).
simplify(0, Z, Z).
simplify(p(X), s(Y), Z) :- simplify(X, Y, Z).
simplify(s(X), p(Y), Z) :- simplify(X, Y, Z).
simplify(s(X), Y, Z) :- Y \= p(_), simplify(X, s(Y), Z).
simplify(p(X), Y, Z) :- Y \= s(_), simplify(X, p(Y), Z).
Some tests:
?- simplify(s(p(s(0))), Z).
Z = s(0)
?- simplify(p(s(p(p(0)))), Z).
Z = p(p(0))
?- simplify(p(p(s(s(0)))), Z).
Z = 0
z(0).
z(s(X)) :-
z(X).
z(p(X)) :-
z(X).
z_canonized(Z, C) :-
z_canonized(Z, 0, C).
z_canonized(0, C,C).
z_canonized(s(N), C0,C) :-
z_succ(C0,C1),
z_canonized(N, C1,C).
z_canonized(p(N), C0,C) :-
z_pred(C0,C1),
z_canonized(N, C1,C).
z_succ(0,s(0)).
z_succ(s(X),s(s(X))). % was: z_succ(X,s(X)) :- ( X = 0 ; X = s(_) ).
z_succ(p(X),X).
z_pred(0,p(0)).
z_pred(p(X),p(p(X))).
z_pred(s(X),X).
Yet another answer, coded for fun of it. It first simplifies an expression into an integer and then converts the result into p(...) for negative integers, s(...) for positive integers (excluding zero), and 0 for 0. The standard sign/1 arithmetic function is used to take advantage of first-argument indexing.
simplify(Expression, Result) :-
simplify(Expression, 0, Result0),
Sign is sign(Result0),
convert(Sign, Result0, Result).
simplify(0, Result, Result).
simplify(s(X), Result0, Result) :-
Result1 is Result0 + 1,
simplify(X, Result1, Result).
simplify(p(X), Result0, Result) :-
Result1 is Result0 - 1,
simplify(X, Result1, Result).
convert(-1, N, p(Result)) :-
N2 is N + 1,
Sign is sign(N2),
convert(Sign, N2, Result).
convert(0, _, 0).
convert(1, N, s(Result)) :-
N2 is N - 1,
Sign is sign(N2),
convert(Sign, N2, Result).
OK, another "fun" solution. This one works in ECliPSe and uses non-standard append_strings, which is a strings' analog of lists' append:
simplify(X, Z) :-
term_string(X, Xstr),
( append_strings(Middle, End, Xstr),
(
append_strings(Begin, "s(p(", Middle)
;
append_strings(Begin, "p(s(", Middle)
) ->
append_strings(NewEnd, "))", End),
append_strings(Begin, NewEnd, Zstr),
term_string(Ztemp, Zstr),
simplify(Ztemp, Z)
;
Z = X
).
This is my answer:
simplify(X, Z) :- simplify(X, 0, 0, Z).
simplify(0, 0, X, X).
simplify(0, X, 0, X) :- X \= 0.
simplify(0, p(X), s(Y), Z) :- simplify(0, X, Y, Z).
simplify(p(X), P, S, Z) :- simplify(X, p(P), S, Z).
simplify(s(X), P, S, Z) :- simplify(X, P, s(S), Z).
I'm dividing input structure into two chains of ps and ss and then I am removing one by one from both chains. When one of them ends, the other one becomes the result of operation. I think it is quite efficient.
I was inspired by Paulo's submission to do a variant of the "Count the p's and s's" approach:
simplify(Exp, Simp) :-
exp_count(Exp, Count),
exp_count(Simp, Count).
exp_count(Exp, C) :-
exp_count(Exp, 0, C).
exp_count(s(X), A, C) :-
( nonvar(C)
-> A < C
; true
),
A1 is A + 1,
exp_count(X, A1, C).
exp_count(p(X), A, C) :-
( nonvar(C)
-> A > C
; true
),
A1 is A - 1,
exp_count(X, A1, C).
exp_count(0, C, C).

Implement a predicate subtraction

So far, my program can add two numbers together.
s(0) represents 1, s(s(0)) represents 2 and so on
p(0) represents -1, p(p(0)) is -2 etc.
I want to be able to call a program such that
add2(s(s(0)), p(0), Z).
returns
Z = s(0).
My code is as follows:
numeral(0).
numeral(s(X)) :- numeral(X).
add(0,X,X).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
numeral(X+Y) :- numeral(X), numeral(Y).
add2(X,Y,Z):-add(X,Y,Z).
add2(X+Y, Z,A) :-add(X,Y,R),add2(R,Z,A).
add2(Z,X+Y,A) :-add(X,Y,R),add2(Z,R,A).
numeral(p(X)) :- numeral(X).
add2(p(X),Y,p(Z)) :- add2(X,Y,Z).
p(s(X)) =:= 0.
s(p(X)) =:= 0.
My logic was that if p(s(0)) was in the list, it would just equate it to 0.. I was wrong, however. Does anybody know where to go with this?
Each numeral could be represented only in one of these 3 ways:
0 - null;
s(X) - next, where X is numeral;
p(X) - previous, where X is numeral;
add2/3 should take 2 numerals and return sum of them. It could be defined manually for each possible arguments:
add2(0, 0, 0).
add2(0, s(X), Y) :- Y = s(X).
add2(0, p(X), Y) :- Y = p(X).
add2(s(X), 0, Y) :- Y = s(X).
add2(s(X), s(Y), Z) :- add2(X, Y, s(s(Z))).
add2(s(X), p(Y), Z) :- add2(X, Y, Z).
add2(p(X), 0, Y) :- Y = p(X).
add2(p(X), s(Y), Z) :- add2(X, Y, Z).
add2(p(X), p(Y), Z) :- add2(X, Y, p(p(Z))).
Works well:
?- add2(s(s(0)), p(0), Z).
Z = s(0) .
It is notable that many cases of add2/3 rule is actually overlapped and could be eliminated:
add2(0, X, X).
add2(X, 0, X).
add2(s(X), s(Y), Z) :- add2(X, Y, s(s(Z))).
add2(s(X), p(Y), Z) :- add2(X, Y, Z).
add2(p(X), s(Y), Z) :- add2(X, Y, Z).
add2(p(X), p(Y), Z) :- add2(X, Y, p(p(Z))).

Resources