Trying to check lines are between 2 points that exist, Prolog - prolog

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.

Related

Find parameter values that satsify logical formula in Prolog

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.

Prolog only check variable is instantiated

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.

How to return two values from a basic predicate(?) in Prolog?

I just started going over Prolog about an hour ago and have already stumbled into a slight problem I am unsure about. I am writing a predicate (or function?) that takes a list and returns the min and max values. Right now, I am just looking at one of the special cases when the list has 1 item. For example, if you query minmax([5], X, Y). I want the predicate to return X=5 Y=5. I have this code:
minmax([X], X, X).
but it is returning X = Y, Y = 5. I know it is a true statement and trivial, but is there a way I can return X=5,Y=5 ???
It is returning what you think it is. X is 5 as is Y. The values are unified and so the interpreter shows the message X=Y, Y=5. You need to get out the Prolog textbook and read up on unification of terms.
You could just as easily say
foo(A,B) :- A = 5 , B is (A+A)/2 .
and query it:
?- foo(X,Y).
and get the same result. In the Prolog universe, there is only ever a single instance of the integer 5.
X=Y, Y=5 means that X and Y are now both equal to 5. It's just a different way of saying that; you really shouldn't care. If you print both values, you'll just get 5:
?- [user].
|: print_stuff :-
|: X = Y,
|: Y = 5,
|: write('X = '), writeln(X),
|: write('Y = '), writeln(Y).
|: % user://1 compiled 0.02 sec, 2 clauses
true.
?- print_stuff.
X = 5
Y = 5
true.

Implement a Prolog predicate that say if an element belong to a list. Problems with not numerical lists

I am studying Prolog for an university exam and I have problems with this exercise:
Implement the predicate not_member(X,L) that is TRUE if the element X does not belong to the list L.
If my reasoning is correct, I have found a solution:
% FACT (BASE CASE): It is TRUE that X is not in the list if the list is empty.
not_member(_,[]).
% RULE (GENERAL CASE): If the list is non-empty, I can divide it in its Head
% element and the sublist Tail. X does not belong to the list if it is different
% from the current Head element and if it does not belong to the sublist Tail.
not_member(X,[Head|Tail]) :-
X =\= Head,
not_member(X,Tail).
This code works well with lists of numbers, as the following queries show:
2 ?- not_member(4, [1,2,3]).
true.
3 ?- not_member(1, [1,2,3]).
false.
With lists having some non-numerical elements, however,
it does not work and reports an error:
4 ?- not_member(a, [a,b,c]).
ERROR: =\=/2: Arithmetic: `a/0' is not a function
Why?
Let's check the documentation!
(=\=)/2 is an arithmetic operator.
+Expr1 =\= +Expr2
True if expression Expr1 evaluates to a number non-equal to Expr2.
You have to use (\=)/2 to compare two generic terms:
not_member(_, []) :- !.
not_member(X, [Head|Tail]) :-
X \= Head,
not_member(X, Tail).
and:
?- not_member(d, [a,b,c]).
true.
Use prolog-dif to get logically sound answers—for both ground and non-ground cases!
Just like in this answer, we define non_member(E,Xs) as maplist(dif(E),Xs).
Let's put maplist(dif(E),Xs) and not_member(E,Xs) by #Haile to the test!
?- not_member(E,[1,2,3]).
false. % wrong! What about `E=4`?
?- maplist(dif(E),[1,2,3]).
dif(E,1), dif(E,2), dif(E,3). % success with pending goals
Is it steadfast? (For more info on this important issue, read
this, this, this, and this answer.)
?- E=d, not_member(E,[a,b,c]).
E = d.
?- not_member(E,[a,b,c]), E=d.
false. % not steadfast
?- E=d, maplist(dif(E),[a,b,c]).
E = d.
?- maplist(dif(E),[a,b,c]), E=d. % steadfast
E = d.
Let's not forget about the most general use!
?- not_member(E,Xs).
Xs = []. % a lot of solutions are missing!
?- maplist(dif(E),Xs).
Xs = []
; Xs = [_A] , dif(E,_A)
; Xs = [_A,_B] , dif(E,_A), dif(E,_B)
; Xs = [_A,_B,_C], dif(E,_A), dif(E,_B), dif(E,_C)
...

Prolog Beginner: How to unify with arithmetic comparison operators or how to get a set var to range of values

I am new to Prolog. I need to write an integer adder that will add numbers between 0-9 to other numbers 0-9 and produce a solution 0-18. This is what I want to do:
% pseudo code
add(in1, in2, out) :-
in1 < 10,
in2 < 10,
out < 18.
I would like to be able to call it like this:
To check if it is a valid addition:
?- add(1,2,3).
true.
?- add(1,2,4).
false.
With one missing variable:
?- add(X,2,3).
X = 1.
?- add(1,4,X).
X = 5.
With multiple missing variables:
?- add(X,Y,Z).
% Some output that would make sense. Some examples could be:
X=1, Y=1, Z=2 ;
X=2, Y=1, Z=3 ......
I realize that this is probably a pretty simplistic question and it is probably very straightforward. However, according to the Prolog tutorial I am using:
"Unlike unification Arithmetic Comparison Operators operators cannot be used to give values to a variable. The can only be evaluated when every term on each side have been instantiated."
All modern Prolog systems provide finite domain constraints, which are true relations that can (in contrast to more low-level arithmetic predicates like is/2 and >/2) be used in all directions. In SWI-Prolog:
:- use_module(library(clpfd)).
plus(X, Y, Z) :-
[X,Y] ins 0..9,
X + Y #= Z.
Results for your examples:
?- plus(1,2,3).
true.
?- plus(1,2,4).
false.
?- plus(X,2,3).
X = 1.
?- plus(1,4,X).
X = 5.
?- plus(X,Y,Z).
X in 0..9,
X+Y#=Z,
Y in 0..9,
Z in 0..18.
Since the predicate can be used in all directions, it does no longer make sense to call it "add/3", as that would imply a direction, but the predicate truly describes when the relation holds and is thus more general.
What about this?:
add(X,Y,Z) :-
Z is X + Y,
X < 10,
Y < 10,
Z < 19.
Problem: this works nicely for queries of the form add(1,1,X) because Z's instantiated before the < calls, but fails when you ask add(X,1,2). You could use var/1 to distinguish the kind of query (var/1 tells you whether a variable's uninstantiated or not), but that sounds like a lot of pain.
Solution:
lessThanTen(9).
lessThanTen(8).
lessThanTen(7).
lessThanTen(6).
lessThanTen(5).
lessThanTen(4).
lessThanTen(3).
lessThanTen(2).
lessThanTen(1).
lessThanTen(0).
addSimple(Add1,Add2,Sol) :-
lessThanTen(Add1),
lessThanTen(Add2),
Sol is Add1+Add2.

Resources