Implement a predicate subtraction - prolog

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))).

Related

How to implement Peano numbers exponentiation in 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.

Given values x and y return rule name if it is true

This is my prolog file.
male(bob).
male(john).
female(betty).
female(dana).
father(bob, john).
father(bob, dana).
mother(betty, john).
mother(betty, dana).
husband(X, Y) :- male(X), mother(Y, Z), father(X, Z).
wife(X, Y) :- female(X), father(Y, Z), mother(X, Z).
son(X, Y) :- male(X), mother(Y, X);female(X), father(Y, X).
daughter(X, Y) :- female(X), mother(Y, X);female(X), father(Y, X).
sister(X, Y) :- female(X), mother(Z, X), mother(Z, Y), X \= Y.
brother(X, Y) :- male(X), mother(Z, X), mother(Z, Y), X \= Y.
I want a name of rule if it returns true for any value x or y.
Let's say x = betty and y = john.
mother(betty, john). <- this will meet so my rule should return 'mother'.
Similarly if any other rule or fact meets true for some value x, y it should return that rule name.
How can I achieve something like that?
could be easy as
query_family(P1, P2, P) :-
% current_predicate(P/2),
member(P, [father, mother, husband, wife, son, daughter, sister, brother]),
call(P, P1, P2).
that gives
?- query_family(betty, john, R).
R = mother ;
false.
?- query_family(betty, X, R).
X = john,
R = mother ;
X = dana,
R = mother ;
X = bob,
R = wife ;
X = bob,
R = wife ;
false.
the semicolon after the answer means 'gimme next'
$ swipl
?- ['facts'].
?- setof( Functor,
Term^(member(Functor, [father, mother, husband, wife, son, daughter, sister, brother]),
Term =.. [Functor, betty, john],
once(Term)),
Answer).
Answer = [mother].
?-
If you want to avoid having to specify the list of functors of interest, you could use current_predicate(F/2).

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).

Prolog: how can i count number in prolog?

if the goal can (5,3) the out put could be 5,4,3 this my code found big error
predicates
count(integer, integer)
clauses
count(X, Y) :- X > Y, write(3), !.
count(X < Y) :- X > Y, write(X), nl, X1 = X-1, count(X1, Y).
count(X,X):-write(X),nl.
count(X,Y):-X<Y,write(X),nl,X1 is X+1,count(X1,Y).

Define a connectivity graph in Prolog

I'm continuing some researches in lattices and semilattices and suddenly having this question.
Basically, we have a RelationList of [a,b] pairs, which means that (a,b) is an edge. Now we should know, is a graph formed by this RelationList 1-connectivity or not.
By the way, we have an ordered graph, so order of (a,b) is important.
clear_link(X, Y, RelationList) :-
(member([X,Y], RelationList)
;
member([Y,X], RelationList)),
X =\= Y.
linked(X, Y, RelationList) :-
clear_link(X, Y, RelationList),
!.
linked(X, Y, RelationList) :-
clear_link(X, Z, RelationList),
linked(Z, Y, RelationList).
simple_connect(RelationList, E) :-
forall((member(X, E),
member(Y, E), X < Y),
linked(X, Y, RelationList)).
But, for 6-element graph I have stackoverflow.
?- simple_connect([[2,1],[2,3],[4,3],[4,5],[6,5]],[1,2,3,4,5,6]).
ERROR: Out of local stack
Am I defining it wrong?
I've correct some. Now it's fine
clear_link(X, Y, RelationList) :-
member([X,Y], RelationList),
X =\= Y.
linked(X, Y, RelationList) :-
clear_link(X, Y, RelationList),
!.
linked(X, Y, RelationList) :-
clear_link(X, Z, RelationList),
linked(Z, Y, RelationList),
!.
simple_connect(RelationList, E) :-
forall((member(X, E),
member(Y, E), X < Y),
linked(X, Y, RelationList)).
connective_graph(RelationList, E) :-
findall(Relation, (
member(X, RelationList),
sort(X, Relation)
),SortRelationList),
simple_connect(SortRelationList, E).
And
?- connective_graph([[2,1],[2,3],[4,3],[4,5],[6,5]],[1,2,3,4,5,6]).
true.
?- connective_graph([[2,1],[4,3],[4,5],[6,5]],[1,2,3,4,5,6]).
false.
Right answer (copy to post)
connected(X, Y, RelationList) :-
(member([X,Y], RelationList);
member([Y,X], RelationList)).
path(X, Y, RelationList, Path) :-
travel(X, Y, RelationList, [X], ReversePath),
reverse(ReversePath, Path),!.
travel(X, Y, RelationList, Point, [Y | Point]) :-
connected(X, Y, RelationList).
travel(X, Y, RelationList, Visited, Path) :-
connected(X, Z, RelationList),
Z =\= Y,
\+member(Z, Visited),
travel(Z, Y, RelationList, [Z|Visited], Path).
connective_graph(RelationList, E) :-
forall((member(X, E),
member(Y, E),
X < Y)
,path(X,Y,RelationList,_)).

Resources