I have a fact base of a single logical formula, e.g.
check(A,B) :- A,B.
I can query check(true,true). or check(true,false). and the compiler will give correct results. But I would like to also make queries where some parameters are variables, to obtain all values of those variables that make the query true. E.g., I'd like to query check(X,Y). and obtain X=true, Y=true., or check(X,true) and obtain X=true. However, I can't get it to work even for this trivial case, nor find the solution anywhere. All queries with variables return Arguments are not sufficiently instantiated.
I've also tried findall(X,check(true,X),Solution). and various variants using bagof or setof.
check_both(X, Y) :-
check_single(X),
check_single(Y).
check_single(true) :- !.
check_single(X) :- call(X).
Results in swi-prolog:
?- check_both(X, Y).
X = Y, Y = true.
?- X=1, check_both(X=1, Y).
X = 1,
Y = true.
?- X=1, check_both(X=2, Y).
false.
?- X=1, check_both(true, X=1).
X = 1.
?- X=1, check_both(true, X=2).
false.
?- member(X, [a, b]), check_both(X=Y, true).
X = Y, Y = a ;
X = Y, Y = b.
Related
I have an add2 predicate which resolves like this where s(0) is the successor of 0 i.e 1
?- add2(s(0)+s(s(0)), s(s(0)), Z).
Z = s(s(s(s(s(0)))))
?- add2(0, s(0)+s(s(0)), Z).
Z = s(s(s(0)))
?- add2(s(s(0)), s(0)+s(s(0)), Z).
Z = s(s(s(s(s(0)))))
etc..
I'm trying to do add in a predecessor predicate which will work like so
?- add2(p(s(0)), s(s(0)), Z).
Z = s(s(0))
?- add2(0, s(p(0)), Z).
Z = 0
?- add2(p(0)+s(s(0)),s(s(0)),Z).
Z = s(s(s(0)))
?- add2(p(0), p(0)+s(p(0)), Z).
Z = p(p(0))
I can't seem to find a way to do this. My code is below.
numeral(0).
numeral(s(X)) :- numeral(X).
numeral(X+Y) :- numeral(X), numeral(Y).
numeral(p(X)) :- numeral(X).
add(0,X,X).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
add(p(X),Y,p(Z)) :- add(X,Y,Z).
resolve(0,0).
resolve(s(X),s(Y)) :-
resolve(X,Y).
resolve(p(X),p(Y)) :-
resolve(X,Y).
resolve(X+Y,Z) :-
resolve(X,RX),
resolve(Y,RY),
add(RX,RY,Z).
add2(A,B,C) :-
resolve(A,RA),
resolve(B,RB),
add(RA,RB,C).
In general, adding with successor arithmetic means handling successor terms, which have the shape 0 or s(X) where X is also a successor term. This is addressed completely by this part of your code:
add(0,X,X).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
Now you have to make a decision; you can either handle the predecessors and the addition terms here, in add/3, or you can wrap this predicate in another one that will handle them. You appear to have chosen to wrap add/3 with add2/3. In that case, you will definitely need to create a reducing term, such as you've built here with resolve/2, and I agree with your implementation of part of it:
resolve(0,0).
resolve(s(X),s(Y)) :-
resolve(X,Y).
resolve(X+Y,Z) :-
resolve(X,RX),
resolve(Y,RY),
add(RX,RY,Z).
This is all good. What you're missing now is a way to handle p(X) terms. The right way to do this is to notice that you already have a way of deducting by one, by using add/3 with s(0):
resolve(p(X), R) :-
resolve(X, X1),
add(s(0), R, X1).
In other words, instead of computing X using X = Y - 1, we are computing X using X + 1 = Y.
Provided your inputs are never negative, your add2/3 predicate will now work.
In Prolog, is it possible to check if the variable is certain value only if the variable is instantiated.
? - my_rule(X).
my_rule(X):-
X = 4,
write('continue').
Here I am trying to check if the X is 4, if the X is 4 then we continue, but I also want the rule to continue if the X is _, but when it is called with something else, like X is 3 then it should not continue.
So the results would look like this:
?- my_rule(X).
continue
true.
?- my_rule(4).
continue
true.
?- my_rule(3).
false.
Have a look at var/1, atom/1 and ground/1:
var(X) is true if and only if X is a variable.
?- var(X), X= 1.
X = 1.
?- X=1, var(X).
false.
?- X=f(Y), var(X).
false.
atom(X) is true if X is an atom.
?- atom(a).
true.
?- atom(f(a)).
false.
?- atom(X).
false.
ground(X) is true if X is ground (does not contain variables).
?- ground(f(a)).
true.
?- ground(f(X)).
false.
The three predicates are deterministic (i.e. do not backtrack) and you can safely negate them.
Your code become something like this:
my_rule(4) :-
% handle the 4 case
my_rule(X) :-
var(X),
% general case
I'm just not sure if this is, what you want. In most programs, there should be no necessity to handle the variable only case separately. Also be aware that such meta-logical tests are outside the scope of classical logic. If compare the queries X = 1, var(X) and var(X), X = 1, you can see that the conjunction is not commutative anymore but in logic A ∧ B = B ∧ A holds.
You can use double negation ( \+(\+(...)) ):
In your example:
my_rule(X):-
\+(\+(X = 4)),
write('continue').
my_rule(X):-
check(X),
write('continue').
% A fact used to check a value.
check(4).
% A predicate that checks if X is unbound, e.g. a variable.
check(X) :-
var(X).
Verification of desired results.
?- my_rule(X).
continue
X = 4 ;
continue
true.
?- my_rule(4).
continue
true ;
false.
?- my_rule(3).
false.
I have a prolog predicate that takes two parameters (both labelled X here since they should be the same) and compares them to see if they evaluate to the same atom. That is the intent. However, the predicate unexpectedly returns false when both arguments are variables.
I'm trying to define a notion of an expression in sentential logic / propositional calculus being in "implication normal form" in Prolog. Implication normal form here meaning that all connectives are replaced with -> and falsum.
As a base case, I want to say that an expression consisting entirely of an atom is already in normal form with itself.
Here's how I'm attempting to express that. I'm repeating a parameter name instead of doing some type of check of sameness between the parameters.
% foo.P
implication_normal(X, X) :- atom(X).
This incomplete-but-still-useful definition is intended to capture the fact that implication_normal(x, x) is true but implication_normal(x, y) is false.
In some ways it seems to work:
$ swipl -s foo.P
?- implication_normal(x, x).
true.
?- implication_normal(x, y).
false.
?- implication_normal(1, 1).
false.
It does the wrong thing with variables (It should be enumerating pairs of "binding contexts" where X and Z happen to point to the same atom).
?- implication_normal(X, Z).
false.
It also just returns false if you give it the same variable twice.
?- implication_normal(X, X).
false.
for some strange reason, the behavior is correct if you give it a variable and a single atom (and you get failure with an integer).
?- implication_normal(X, z).
X = z.
?- implication_normal(X, 1).
false.
and similarly if the variable is second.
?- implication_normal(z, X).
X = z.
?- implication_normal(1, X).
false.
How do I change the definition of implication_normal so that it enumerates in all the cases where variables are supplied?
The standard atom/1 predicate is a type-checking predicate. It doesn't enumerate atoms. It just deterministically checks if its argument is an atom. Moreover, your definition of the implication_normal /2 predicate attempts to unify its two arguments and, if the unification is successful, calls atom/1 with the resulting term. That's why a call such as implication_normal(X, z) succeeds: X is unified with z and atom(z) is true.
Note that some Prolog systems provide a current_atom/1 that does enumerate atoms. On those systems, you could write instead:
implication_normal(X, X) :- current_atom(X).
Some sample calls using SWI-Prolog:
?- implication_normal(X, Z).
X = Z, Z = '' ;
X = Z, Z = abort ;
X = Z, Z = '$aborted'
...
?- implication_normal(X, X).
X = '' ;
X = abort ;
X = '$aborted' ;
...
?- implication_normal(X, z).
X = z.
?- implication_normal(X, 1).
false.
I am trying to check whether lines are actually between 2 points that exist in the rule set. For example in the code below,
point(a).
point(z).
line(l,k).
line(k,l).
line(k,a).
line(a,z).
line(a,z). is a real line because a and z are both points in the rule set but line(l,k). isn't a real line because l and k aren't real points in the rule set.
I am new to Prolog and would just like some pointers for how to do this.
You could write:
real_line(X,Y):-line(X,Y),point(X),point(Y).
The , in Prolog means logical "and" so the above predicate real_line/2 succeeds when for X,Y holds: line(X,Y) and X is a point and Y is a point.
Some examples:
?- real_line(a,z).
true.
?- real_line(a,k).
false.
?- real_line(l,k).
false.
?- real_line(X,Y).
X = a,
Y = z.
?- real_line(X,z).
X = a.
?- real_line(a,Y).
Y = z.
UPDATE
Based on your comments to find all incorrect lines you could use:
findall(line(X,Y),(line(X,Y), \+ real_line(X,Y)),L).
Example:
?- findall(line(X,Y),(line(X,Y), \+ real_line(X,Y)),L).
L = [line(l, k), line(k, l), line(k, a)].
OR with a fail-driven loop:
write_incorrect_lines:-
line(X,Y),
\+real_line(X,Y),
write(line(X,Y)),
nl,
fail;
true.
Example:
?- write_incorrect_lines.
line(l,k)
line(k,l)
line(k,a)
true.
Can I define a fact of the following form,
test(X, ceiling(sqrt(X))).
Where, X is related to ceiling(sqrt(X)).
I think , I could have done the following to receive the desired output,
test(X, Y) :- Y is ceiling(sqrt(X)).
You can define:test(X, ceiling(sqrt(X))).
This means that you have as fact atoms in the above form so if you query:
?- test(X, ceiling(sqrt(X))).
true.
because you defined this clause.
But note that if you query:
?- test(1.5, 2).
false.
It returns false because 2 is ceiling(sqrt(1.5)) but the predicate is waiting a syntax like ceiling(sqrt(1.5)) and not the result 2.
Another example:
?- test(1.5, Y).
Y = ceiling(sqrt(1.5)).
and
?- test(X,ceiling(sqrt(1.5))).
X = 1.5.
Also notice that :
test(X) :- X is ceiling(sqrt(X)).
is always failing for any input X (because there is no such X that equals to ceiling(sqrt(X)). )and querying test(X) will have instantiation problems due to is/2.
Maybe what you meant to write is:
test(X,X1) :- X1 is ceiling(sqrt(X)).
Sorry but I don't understand your clause
test(X) :- X is ceiling(sqrt(X)).
You're imposing the equation (not assignment: equation) " X = ceiling(sqrt(X)) ".
I think you're intention was
test(X, Y) :- Y is ceiling(sqrt(X)).
Is this what do you want?