Write A Prolog Rule

can you say no u properly

1 Like

Yes

How is distance defined?

Whatever basic way you can think of? Let’s say there’s a 5 by 5 grid and each square is 1 foot

These are the basic ways I think of measuring distance, see: Metric

sure! How would I implement that by making a prolog program?

discrete_metric(a(X,Y),b(X,Y),0) :- !.
discrete_metric(a(X1,_),b(X2,_),1) :-
    X1 \= X2 , !.
discrete_metric(a(_,Y1),b(_,Y2),1) :-
    Y1 \= Y2.

% Enhanced based on comment by Peter

euclidean_metric(a(X1,Y1),b(X2,Y2),Distance) :-
    X is abs(X2 - X1),
    Y is abs(Y2 - Y1),
    (
        X == 0
    ->
        Distance is float(Y)
    ;
        (
            Y == 0
        ->
            Distance is float(X)
        ;
            Distance is sqrt(X**2 + Y**2)
        )
    ).

taxicab_metric(a(X1,Y1),b(X2,Y2),Distance) :-
    X is abs(X2 - X1),
    Y is abs(Y2 - Y1),
    Distance is X + Y.

Test cases

:- begin_tests(metrics).

discrete_metric_case(a(0,0),b(0,0),0).
discrete_metric_case(a(1,0),b(0,0),1).
discrete_metric_case(a(0,1),b(0,0),1).
discrete_metric_case(a(0,0),b(1,0),1).
discrete_metric_case(a(0,0),b(0,1),1).
discrete_metric_case(a(2,3),b(4,5),1).

euclidean_metric_case(a(0,0),b(0,0),0.0).
euclidean_metric_case(a(1,0),b(0,0),1.0).
euclidean_metric_case(a(0,1),b(0,0),1.0).
euclidean_metric_case(a(0,0),b(1,0),1.0).
euclidean_metric_case(a(0,0),b(0,1),1.0).
euclidean_metric_case(a(2,3),b(4,5),2.8284271247461903).

taxicab_metric_case(a(0,0),b(0,0),0).
taxicab_metric_case(a(1,0),b(0,0),1).
taxicab_metric_case(a(0,1),b(0,0),1).
taxicab_metric_case(a(0,0),b(1,0),1).
taxicab_metric_case(a(0,0),b(0,1),1).
taxicab_metric_case(a(2,3),b(4,5),4).

test(discrete_metric,[forall(discrete_metric_case(P1,P2,Distance))]) :-
    discrete_metric(P1,P2,Distance).

test(euclidean_metric,[forall(euclidean_metric_case(P1,P2,Distance))]) :-
    euclidean_metric(P1,P2,Distance).

test(taxicab_metric,[forall(taxicab_metric_case(P1,P2,Distance))]) :-
    taxicab_metric(P1,P2,Distance).

:- end_tests(metrics).

Example run.

?- make.
% c:/users/groot/documents/projects/prolog/swi-discourse_039 compiled 0.00 sec, 0 clauses
% PL-Unit: metrics .................. done
% All 18 tests passed
true.

Or: Distance is float(Y)

1 Like

When writing the code I thought that and did a quick check by Googling and found float/1 when I should have been looking for float/1.

For those not paying attention like me at the time, one is a predicate and one is function. :face_with_monocle:

A simple predicate to return the Cartesian distance between x0, y0 and x1, y1 could look something like.

distance(X0, Y0, X1, Y1, Dx, Dy) :-
    Dx is abs(X1 - X0),
    Dy is abs(Y1 - Y0).

To check if x1, y1 is within the allowed distance maxdx, maxdy from x0, y0 you could use this with say

allowed_distance(Dx, Dy, MaxDx, MaxDy) :-
    Dx =< MaxDx,
    Dy =< MaxDy.

And then the problem could be solved with:

distance(X0, Y0, X1, Y1, Dx, Dy), allowed_distance(Dx, Dy, MaxDx, MaxDy).

A basic concept of Prolog which I certainly struggled with initially is that instead of

f(x) = y

you have f(x,y) which in the documentation would be written something like f(+X:type, -Y:type) to indicate X is an input and Y an output.

For arithmetic functions, SWI Prolog offers a choice of Prolog-style and “traditional” function style: eg there is an abs (+Number, -Absolute) which returns the absolute value as an output argument or abs (+Expr) which can only be used in is clauses as in Y is abs(3 - 2).

Thanks for those who posted! I am learning

Distance is sqrt(X**2 + Y**2)

:thinking:

I apologize, I had misunderstood the **. Should I delete my recent reply?

However, this begs a good question. Prolog, admittedly, doesn’t have as big of resources as say Java or C like I’m used to. How would you advise looking up things like ** besides just googling? Are there specific sites that are helpful? When I want to research something specific Prolog, what is the best way to do so?

With regards to Prolog I don’t know any better than this one, but am all ears if someone has something else.

Unlike other programming languages where you can typically Google for something, with Prolog it comes more from experience and actually doing a class and working through the few classic books. (free books which doesn’t include many of the classics). If you look back in my other post it notes that I often read sections of those books about every month looking for more details on to refresh my memory on how to think about doing it in Prolog. Because Prolog is basically built on top of just unification, it is just a matter of understanding a few basic concepts and applying them. At the abstract level this is pretty standard in Prolog, but when you get closer to the metal, e.g. OS and such, then knowing which predicates to used can often be found in the documentation.

One place I often look for examples is in the SWI-Prolog source code posted on GitHub.

Another repository with SWI-Prolog code is in the packages

Try something and see if it works and then ask questions if stuck. If you read the current post by @emacstheviking you can see another with the same need.

Thanks! I’ll look into the GitHub, keep working on problems on my own, ask questions here, etc. I’m a slow learner, but programming is really fun.

Again, new to the forum. Should I mark one of these answers as “solution” and then somehow close the thread?

You can but others don’t.

Also I don’t think these can be closed. This is not like StackOverflow where every topic is a question and can only have an answer. Some post take on a life of there own and go on for days, e.g. Start of IEEE 754 support

Hi Eric,

Sorry, know you’re probably pretty busy. I was just wondering if you’d be able to add comments to your code just so I can make sure I really understand what each line is doing. If you can’t, no big deal.

It is pretty basic code without anything tricky so really doesn’t need comments. Don’t get me wrong thinking that I am against comments, I am all for them when needed.

Instead it would be better if you asked about what you don’t understand, then I or others can answer those questions individually. But before asking look in Learn Prolog Now! or one of the free books or classic books. Also if you are serious about learning Prolog then get one or more of the classic books.

You should create some test cases and try locations with one or more zero coordinates; if you don’t know why you have something to learn.

Also you don’t add blank lines in a predicate and should indent after the head of the predicate, e.g.

safe(Distance,(X1,Y1),(X2,Y2)) :-
    Distance =< sqrt((Y2-Y1)**2 + (X2-X1)**2).

Thanks for the tips on formatting.

No I didn’t notice anything, but you should always check the corner cases and create test cases. It is a good habit to get into from the start so that when you get to larger projects writing test cases will not be added surprise and if you have proper test cases, the moment something is wrong you will know it versus spending days looking for a bug because the test cases were not compete.