0
votes

I was making a prolog knowledge base to implement geometry rules. When testing if a rectangle had a right angle, I found two answers.

?- rect_tri(triangle(line(point(0,0),point(0,1)),line(point(0,1),point(1,0)),line(point(1,0),point(0,0)))).
true ;
false.

Here is the kwnoledge base:

point(X,Y).
line(X,Y) :- X = point(A,B), Y = point(C,D), not(X = Y). 
len(X,R) :- X = line(P,Q), P = point(A,B), Q = point(C,D), not(P = Q), 
    R is sqrt((A - C) * (A - C) + (B - D) * (B - D)).
triangle(X,Y,Z) :- X = point(A,B), Y = point(C,D), Z = point(E,F),
    not(X = Y), not(X = Z), not(Y = Z), 
    L1 = line(X,Y), L2 = line(X,Z), L3 = line(Y,Z),
    len(L1,G), len(L2,H), len(L3,I),
    G + H > I, G + I > H, H + I > G.
triangle(X,Y,Z) :- X = line(A,B), Y = line(B,C), line(A,C),
    len(X,G), len(Y,H), len(Z,I),
    G + H > I, G + I > H, H + I > G.
rect_tri(X) :- X = triangle(A,B,C), len(A,G), len(B,H), len(C,I),
    (G is sqrt(H * H + I * I); 
        H is sqrt(G * G + I * I); 
        I is sqrt(H * H + G * G)).

When tracing, I found that the answer true comes when prolog hits the line H is sqrt(G * G + I * I), and false when it evaluates the last line.

I don't want the last evaluation to occur, because I want it to exit when a true has been found.

1
How about adding a one_rect_tri(X) :- once(rect_tri(X)). and calling that instead of rect_tri/1? - Daniel Lyons

1 Answers

2
votes

Daniel comment probably shows the most sensible way to solve your problem. Some other option...

in modern compilers there is the if/then/else construct:

rect_tri(X) :- X = triangle(A,B,C), len(A,G), len(B,H), len(C,I),
    (  G is sqrt(H * H + I * I)
    -> true
    ;  H is sqrt(G * G + I * I)
    -> true
    ;  I is sqrt(H * H + G * G)
    ).

You could as well use cuts (old fashioned way, somewhat more readable here):

rect_tri(X) :- X = triangle(A,B,C), len(A,G), len(B,H), len(C,I),
    (  G is sqrt(H * H + I * I), !
    ;  H is sqrt(G * G + I * I), !
    ;  I is sqrt(H * H + G * G)
    ).