"Return" 0 if odd and same value if even in prolog - prolog

I'm new to prolog so the concept of unifying is still new, so bear with me.
I want something like:
pair(X,Y)
That works like this:
?- pair(4,Y).
Y = 4,
?- pair(3,Y).
Y = 0,
But I don't really know how to do this. I know you can use something like X mod 2 =:= 0 which is true or false, but I don't know how to make "if this than that" code in prolog's way.

There are several ways to express a conditional statement in Prolog, besides using CLPFD (Constraint Logic Programming over Finite Domains):
1) make several statements, one for each case you are considering, and let Prolog execution mechanism find the one that is appropriate:
pair(X,Y) :- even(X), !, Y = X. % 'if X is even then Y = X'
pair(_,0). % 'else Y = 0'
In the second case here the unification is implicit, but in the first case it is explicit.
The _ symbol is a syntactic sugar for an 'anonymous variable', that is a variable for whose bindings we do not care and that we do not use.
The cut operator ! is used in the first clause to tell Prolog that it should not try to find other solutions for the Y if the first clause succeeds (like, backtracking and trying the second clause):
% without cut | % with cut
?- pair(4,Y). | ?- pair3(4,Y).
|
Y = 4 ? ; | Y = 4 ? ;
|
Y = 0 ? ; % <- wrong behaviour! | no.
|
no |
2) use the (Condition -> ThenStatement ; ElseStatement) if-then-else construct:
pair(X,Y) :- (even(X) -> Y = X ; Y = 0).
No cuts are allowed in the Condition argument. The first solution of the Condition is used.
3) some systems have the if/3 predicate, that is evaluated as if(Condition,ThenStatement,ElseStatement):
pair(X,Y) :- if( even(X), Y = X, Y = 0).
No cuts are allowed in the Condition argument.

Related

How to stop backtracking and end the recursion in Prolog

I'm currently learning SWI-Prolog. I want to implement a function factorable(X) which is true if X can be written as X = n*b.
This is what I've gotten so far:
isTeiler(X,Y) :- Y mod X =:= 0.
hatTeiler(X,X) :- fail,!.
hatTeiler(X,Y) :- isTeiler(Y,X), !; Z is Y+1, hatTeiler(X,Z),!.
factorable(X) :- hatTeiler(X,2).
My problem is now that I don't understand how to end the recursion with a fail without backtracking. I thought the cut would do the job but after hatTeilerfails when both arguments are equal it jumps right to isTeiler which is of course true if both arguments are equal. I also tried using \+ but without success.
It looks like you add cuts to end a recursion but this is usually done by making rule heads more specific or adding guards to a clause.
E.g. a rule:
x_y_sum(X,succ(Y,1),succ(Z,1)) :-
x_y_sum(X,Y,Z).
will never be matched by x_y_sum(X,0,Y). A recursion just ends in this case.
Alternatively, a guard will prevent the application of a rule for invalid cases.
hatTeiler(X,X) :- fail,!.
I assume this rule should prevent matching of the rule below with equal arguments. It is much easier just to add the inequality of X and Y as a conditon:
hatTeiler(X,Y) :-
Y>X,
isTeiler(Y,X),
!;
Z is Y+1,
hatTeiler(X,Z),
!.
Then hatTeiler(5,5) fails automatically. (*)
You also have a disjunction operator ; that is much better written as two clauses (i drop the cuts or not all possibilities will be explored):
hatTeiler(X,Y) :- % (1)
Y > X,
isTeiler(Y,X).
hatTeiler(X,Y) :- % (2)
Y > X,
Z is Y+1,
hatTeiler(X,Z).
Now we can read the rules declaratively:
(1) if Y is larger than X and X divides Y without remainder, hatTeiler(X,Y) is true.
(2) if Y is larger than X and (roughly speaking) hatTeiler(X,Y+1) is true, then hatTeiler(X, Y) is also true.
Rule (1) sounds good, but (2) sounds fishy: for specific X and Y we get e.g.: hatTeiler(4,15) is true when hatTeiler(4,16) is true. If I understand correctly, this problem is about divisors so I would not expect this property to hold. Moreover, the backwards reasoning of prolog will then try to deduce hatTeiler(4,17), hatTeiler(4,18), etc. which leads to non-termination. I guess you want the cut to stop the recursion but it looks like you need a different property.
Coming from the original property, you want to check if X = N * B for some N and B. We know that 2 <= N <= X and X mod N = 0. For the first one there is even a built-in called between/2 that makes the whole thing a two-liner:
hT(X,B) :-
between(2, X, B),
0 is (X mod B).
?- hT(12,X).
X = 2 ;
X = 3 ;
X = 4 ;
X = 6 ;
X = 12.
Now you only need to write your own between and you're done - all without cuts.
(*) The more general hasTeiler(X,X) fails because is (and <) only works when the right hand side (both sides) is variable-free and contains only arithmetic terms (i.e. numbers, +, -, etc).
If you put cut before the fail, it will be freeze the backtracking.
The cut operation freeze the backtracking , if prolog cross it.
Actually when prolog have failed, it backtracks to last cut.
for example :
a:- b,
c,!,
d,
e,!,
f.
Here, if b or c have failed, backtrack do not freeze.
if d or f have failed, backtrack Immediately freeze, because before it is a cut
if e have failed , it can backtrack just on d
I hope it be useful

Prolog- How does a cut work in combination with OR operator?

I have written this little program:
married(guy1, fem1).
married(guy2, fem2).
married_to(X,Y):-!, married(X,Y); married(Y,X).
Prints:
X = guy1,
Y = fem1 ;
X = guy2,
Y = fem2.
My purpose was to print the married couples but one time each. The above rule works for me, but I can't understand why! How does this work?
What's the difference with that:
married_to(X,Y):- married(X,Y); married(Y,X).
This prints:
X = guy1,
Y = fem1 ;
X = guy2,
Y = fem2 ;
X = fem1,
Y = guy1 ;
X = fem2,
Y = guy2.
The cut commits execution to the first branch on the disjunction. Thus your rule:
married_to(X,Y):-!, married(X,Y); married(Y,X).
is operationally the same as:
married_to(X,Y):-!, married(X,Y).
And, given that there are no other clauses for the married_to /2 predicate, equivalent to:
married_to(X,Y):- married(X,Y).
imagine you have the equivalent definition married_to(X,Y):- true, !, married(X,Y) ; married(Y,X).. If true were to fail, then we'd jump to the alternative, but since it's not going to, we're firmly on the consequent branch (of the disjunction).
IOW your code is
married_to(X,Y):- ( !, married(X,Y) ) ; ( married(Y,X) ).
and not
married_to(X,Y):- !, ( married(X,Y) ; married(Y,X) ).
It is actually equivalent to
married_to(X,Y):- !, married(X,Y).
married_to(X,Y):- married(Y,X).
Perhaps with this it is easier to get a "feeling" for what is going on here. Obviously, the second clause of the predicate is cut off. :) We're committed to the first clause, the second doesn't get a chance to work at all.

deduction from two goals

Suppose I have such goals:
times(0,_,0). % zero times X is zero
times(X,Y,Z) :- times(Y,X,Z) ,!. % X * Y = Y * X
When I try to ask:
?- times(0,1,X).
I get the double answer :
X = 0 ;
X = 0.
Possibly because first answer is deduced from the fact and second - from the rule.
Question - how to make prolog to give only one answer instead of two ?
add a cut to 'confirm' the first choice:
times(0,_,0) :- !.
or ban the 0 from the second:
times(X,Y,Z) :- X \= 0, times(Y,X,Z).
I've deleted the cut, but leave it if there are more rules.
But I think the 'reflexivity' rule will put you in trouble, with undue recursion.

How to Print numbers from 1 to 100 in Prolog?

The following code is a Prolog code which gives all integers greater than 0. Each time i put ; in the interpreter, it gives the next number:
is_integer(0).
is_integer(X) :- is_integer(Y),X is Y+1.
Is there a way where it gives numbers between 0 and 100 only. When it reaches 100 it should stop.
There is a built-in predicate between/3 for that purpose in B, Ciao, SICStus (library), SWI, YAP, XSB (library).
?- between(0,100,X).
X = 0
; X = 1
; ...
; X = 100.
If you start to learn Prolog, better try to use s(X) numbers first which are much easier to understand and reason about. The same example, but only going up to 3:
?- nat_nat_sum(N,_,s(s(s(0)))).
with the definition:
nat_nat_sum(0,I,I).
nat_nat_sum(s(I),J,s(K)) :-
nat_nat_sum(I,J,K).
What a nice quiz. It exemplifies very well how difficult can be to control the recursion with the minimal tools that Prolog defines. We must commit our solutions to values lower than the predefined limit, restricting the otherless unbound search:
is_integer(0).
is_integer(X) :-
is_integer(Y),
( Y >= 100, ! ; X is Y + 1 ).
Here is the trace output limiting the range to 3 (i.e. ... Y >= 3, ! ; ...)
?- is_integer(X).
X = 0 ;
X = 1 ;
X = 2 ;
X = 3 ;
true.

Avoiding the use of cut in Prolog absolute value predicate

I have implemented the following function in prolog with the following code:
abs2(X, Y) :- X < 0, Y is -X.
abs2(X, X) :- X >= 0, !.
How can I implement this function without the use of cut ("!")?
There's the "hidden" cut in the if-then-else construct of Prolog:
abs2(X,Y) :- X < 0 -> Y is -X ; Y = X.
It is something of a quirk, but Prolog does not backtrack on the subgoal that forms the "premise" of an if-then or if-then-else construct. Here, if X < 0 succeeds the first try, then the choice of "then" clause over "else" clause is committed (hence the description of this behavior as a "hidden" cut).
There is more of a role for a cut in the first clause of the predicate abs2/2 as written in the question. As Nicholas points out, the cut at the end of the second clause doesn't have any effect (there are no choice points left when you get there). But as Kaarel points out, there is a choice point left open if the first clause succeeds.
So what I would have written, allowing the use of a cut, is this:
abs2(X,X) :- X >= 0, !.
abs2(X,Y) :- Y is -X.
Nicholas's comments also suggest ways to "arithmetize" the absolute value (rather than use a logic definition) and avoid "cut" that way.
My prolog is a bit rusty, but why do you even need the cut? If you write the predicate properly, backtracking can't succeed, so the cut is unnecessary:
abs(X, Y) :- number(X) , X < 0 , Y is -X .
abs(X, X) :- number(X) , X >= 0 .
No need to use prolog-cut!
Simply write:
abs2(X,Y) :- Y is abs(X).

Resources