vw511
vw511

Reputation: 171

How to specify a range in nondet (to avoid choicepoints in PL Unit Testing)

I wrote some tests for some Prolog codes and got "Test succeeded with choicepoint" warning. Here's one of my tests:

test(overlap_intervals):-
    overlap_intervals([0, 10], [5, 15]).

Here's the codes:

%% precondition: X1<Y1 and X2<Y2
overlap_intervals([X1,Y1], [X2,Y2]):-
    (X1<X2, Y1<Y2, Y1>X2); !,
    (X1>X2, Y1>Y2, Y1<X2).

I saw from other posts that I can use "nondet" test(foo, nondet) :- .... to avoid choice points, such as:

test(member, all(X == [a,b,c])) :-
    member(X, [a,b,c]). % quoting Prolog document

However, I'm dealing with intervals in my case. The "nondet" would be a range of numbers, rather than an exhaustible list. For example (which apparently doesn't work but gets my goal across):

test(overlap_intervals, all(Y<10, Y>0)):-
    overlap_intervals([0, 10], [Y, 15]).

Can someone explain why there are choicepoints and how to avoid them in my case?

Upvotes: 1

Views: 151

Answers (1)

Isabelle Newbie
Isabelle Newbie

Reputation: 9378

There is a choicepoint because you got confused about precedence when mixing ; and !. As usual in logic, and (,) binds stronger than or (;).

Better ways of writing your predicate would be:

overlap_intervals_2([X1,Y1], [X2,Y2]):-
    (   (X1<X2, Y1<Y2, Y1>X2),
        !
    ;   (X1>X2, Y1>Y2, Y1<X2) ).

or (preferred):

overlap_intervals_3([X1,Y1], [X2,Y2]):-
    (X1<X2, Y1<Y2, Y1>X2),
    !.
overlap_intervals_3([X1,Y1], [X2,Y2]):-
    (X1>X2, Y1>Y2, Y1<X2).

These alternative definitions make it clearer where the cut belongs, highlighting that it was misplaced in your version. Tests:

?- overlap_intervals([0, 10], [5, 15]).
true ;
false.

?- overlap_intervals_2([0, 10], [5, 15]).
true.

?- overlap_intervals_3([0, 10], [5, 15]).
true.

Note that none of these definitions cover the case where one interval is contained within another one. I would say that overlap_intervals([0, 10], [1, 9]) should be true, but the exact meaning of the predicate depends on your application, of course.

As for your use of all in a test head, all(between(0, 10, Y)) should work, I think (not tested).

Upvotes: 1

Related Questions