# How to find unexpected choicepoints?

**URL:** <https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423>\
**Category:** Help!\
**Tags:** how-to\
**Created:** [May 28, 2020, 11:01pm UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423 "2020-05-28T23:01:57Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![stuz5000](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/stuz5000/32/940_2.png) [@stuz5000](https://swi-prolog.discourse.group/u/stuz5000)\
**Post date:** [May 28, 2020, 11:01pm UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/1 "2020-05-28T23:01:57Z")

</div>

I have a reasonably complex predicate that’s giving me more solutions than expected - it is unexpectedly not deterministic.  
Is there a trick to debugging this kind of situation? For example, is it possible to set a breakpoint each time a new choicepoint is created?

Thanks in advance,

- Stuart

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [May 28, 2020, 11:29pm UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/2 "2020-05-28T23:29:11Z")

</div>

Have you checked: [Bug hunting toolbox](https://swi-prolog.discourse.group/t/bug-hunting-toolbox/710)

---

<div class="post-metadata">

**Author:** ![swi](https://avatars.discourse-cdn.com/v4/letter/s/51bf81/32.png) [@swi](https://swi-prolog.discourse.group/u/swi)\
**Post date:** [May 29, 2020, 12:20am UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/3 "2020-05-29T00:20:20Z")

</div>

In general when you get too many answers is because you are missing an extra predicate in the conjunction.

```prolog
p(A) :-
  a(A),
  b(A).

```

will produce (in general) more answers than:

```prolog
p(A) :-
  a(A),
  b(A),
  c(A).

```

where c/1 restrains the conditions some more.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [May 29, 2020, 12:34am UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/4 "2020-05-29T00:34:05Z")

</div>

You can use setup\_call\_cleanup/3 to check for individual calls being deterministic, but it’s a cumbersome to do this – you could use the wrapping technique (using wrap\_predicate/4) from [library(rdet)](https://www.swi-prolog.org/pack/list?p=rdet) to make this easier.

---

<div class="post-metadata">

**Author:** ![stuz5000](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/stuz5000/32/940_2.png) [@stuz5000](https://swi-prolog.discourse.group/u/stuz5000)\
**Post date:** [May 29, 2020, 4:36am UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/5 "2020-05-29T04:36:46Z")

</div>

Thanks all. Here’s what I did.

```prolog
f(X):- % problem predicate. Unexpected multiple solutions.

```

Replace with:

```prolog
f_(X):- % rename the problem predicate

f(X):-
   f_(X), gtrace.

?- f(X).

```

… and gtrace will continue at the problem choicepoint.

---

<div class="post-metadata">

**Author:** ![stuz5000](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/stuz5000/32/940_2.png) [@stuz5000](https://swi-prolog.discourse.group/u/stuz5000)\
**Post date:** [May 29, 2020, 4:51am UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/6 "2020-05-29T04:51:56Z")

</div>

> [@swi](#):
>
> In general when you get too many answers is because you are missing an extra predicate in the conjunction.

… at least in my case, it was because of an overlapping rule definition:

```prolog
%make_trees(Roots, Childre, Trees)
make_trees([], [], [tree(nil,[])]).
make_trees([], [tree(Data,Children)], [tree(Data,Children)]).
make_trees([], [H|T], [tree(nil, [H|T])]).
...

```

…needed to be

```prolog
make_trees([], [], [tree(nil,[])]).
make_trees([], [tree(Data,Children)], [tree(Data,Children)]), !. % Add cut
make_trees([], [H|T], [tree(nil, [H|T])]).
...

```

or

```prolog
make_trees([], [], [tree(nil,[])]). % len ==0
make_trees([], [tree(Data,Children)], [tree(Data,Children)]). % len ==1
make_trees([], [H0, H1|T], [tree(nil, [H0, H1|T])]). % len >=2
...

```

Debugging this kind of thing is a PITA.

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [May 29, 2020, 5:27am UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/7 "2020-05-29T05:27:57Z")

</div>

I struggled with the same problem. My solution was to wrap my “entry point” to the program in a setup-call-cleanup that throws if there is a choice point after the first success, _and test very often during development_ so that I immediately notice any problems.

The predicate itself:

```prolog
goal_is_det(Goal) :-
        setup_call_cleanup(true, Goal, Det = true),
        ( Det == true
        -> true
        ; !,
                throw(error(mode_error(notdet),_))
        ).

```

It seems to provide similar functionality as library(rdet). (But not sure about that).

And of course it only helps if you run your “integration tests” or “end-to-end tests” or whatever you prefer to call them often enough so you notice the problem when you introduce it.

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [May 29, 2020, 5:41am UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/8 "2020-05-29T05:41:57Z")

</div>

I guess you can also use leash/1 for the _redo_ port only on the prediate you are debugging? I wish I had the time to properly document my experiences with debugging in particular, but sadly external circumstances usually force me to move faster than I would like ☹

---

<div class="post-metadata">

**Author:** ![stuz5000](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/stuz5000/32/940_2.png) [@stuz5000](https://swi-prolog.discourse.group/u/stuz5000)\
**Post date:** [May 29, 2020, 5:43am UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/9 "2020-05-29T05:43:26Z")

</div>

rdet looks like a good solution.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [May 29, 2020, 7:09am UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/10 "2020-05-29T07:09:56Z")

</div>

As seen, there are a large number of ways to get more info. My personal solution is typically

```prolog
?- gspy(suspect_pred).
?- go.

```

As the debugger hits `suspect_pred`, use `s` (skip) to jump to the end and examine the choice points in the top-right window. You can click on these to see the source location. You can also use `u` (up) to get to the caller of the open choice point (etc).

If you have a predicate that is most of the time deterministic but under some circumstances not, the rdet or cleanup/2 tricks can help you to fine the problematic case and start the debugger only in that case. I don’t recall using that. But then, experienced Prolog programmers do not make determinism mistakes very often 🙂

Note that there are a number of cases. Fighting determinism this way makes most sense for recursive code that mostly has a procedural flavor. Here, non-determinism kills LCO (Last Call Optimization) making your code a lot slower and using a lot more memory.

In the typical case where a set of predicates define a logic formula that specify valid solutions, backtracking is typically desired. Using cuts to avoid exploring parts of the search space is typically better avoided. Adding additional constraints keeps the logical reading while the semantics of the code with cuts is often hard to grasp. If performance and/or multiple solutions is an issue here, you have some options. Ordering, stratification, distinct/1,2, order\_by/3 may help. Tabling can be attractive as it avoids multiple solution, repeated computation of the same goal, deals with cycles and negation.

**edit** especially for numerical problems, _constraints_ as e.g., library(clpfd) can solve the problem.

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [May 29, 2020, 8:11am UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/11 "2020-05-29T08:11:32Z")

</div>

Thank you for the good summary of the tools available to avoid dangling choice points.

By “dangling choice point” I mean an unintentional, seemingly benign choice point that comes back some time later to bite you in the butt.

> [@jan](#):
>
> If you have a predicate that is most of the time deterministic but under some circumstances not, the rdet or cleanup/2 tricks can help you to fine the problematic case and start the debugger only in that case. I don’t recall using that. But then, experienced Prolog programmers do not make determinism mistakes very often 🙂

🙂 We all must learn to walk before we can run, right?

I think I first heard this from [Chen Stormstout](https://wow.gamepedia.com/Pandaren_Brewmaster_(Warcraft_III)).

Now that I think about it, our oldest daughter started running (sideways and backwards mostly) as soon as she stood up and had to wear a helmet for a while.

---

<div class="post-metadata">

**Author:** ![swi](https://avatars.discourse-cdn.com/v4/letter/s/51bf81/32.png) [@swi](https://swi-prolog.discourse.group/u/swi)\
**Post date:** [May 29, 2020, 2:42pm UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/12 "2020-05-29T14:42:09Z")

</div>

> [@stuz5000](#):
>
> ```prolog
> make_trees([], [], [tree(nil,[])]). % len ==0
> make_trees([], [tree(Data,Children)], [tree(Data,Children)]). % len ==1
> make_trees([], [H0, H1|T], [tree(nil, [H0, H1|T])]). % len >=2
> ...
> 
> ```

This one is better, because you don’t use cuts.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [May 29, 2020, 6:01pm UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/13 "2020-05-29T18:01:57Z")

</div>

> [@Boris](#):
>
> It seems to provide similar functionality as library(rdet). (But not sure about that).

I’d like to make this an option for rdet, but so far haven’t done it. If you want to try it yourself, it’s a 1-line change to `rdet.pl`. (Making it an option would require multiple versions of the `rdet/1` directive.)

The current version of rdet transforms (using wrap\_predicate/4) a call to `Pred` into something like `(Pred->true;throw(...))` … so it’s really a test for whether a predicate that’s expected to succeed actually does succeed (which is _very_ useful in my experience). As a side-effect, it turns `call(Pred)` into `once(Pred)`, which might not be what you want. That’s another change I want to make to rdet, namely changing the call to `Pred` into something like `(Pred*->true;throw(...))`. Not sure when I’ll get around to making these enhancements, but probably soon because they would be useful for me.

[BTW, is the cut in your `goal_is_det/1` needed?]

---

<div class="post-metadata">

**Author:** ![stuz5000](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/stuz5000/32/940_2.png) [@stuz5000](https://swi-prolog.discourse.group/u/stuz5000)\
**Post date:** [May 29, 2020, 6:23pm UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/14 "2020-05-29T18:23:39Z")

</div>

> [@peter.ludemann](#):
>
> As a side-effect, it turns `call(Pred)` into `once(Pred)` , which might not be what you want. That’s another change I want to make to rdet, namely changing the call to `Pred` into something like `(Pred*->true;throw(...))` . Not sure when I’ll get around to making these enhancements, but probably soon

It would be nice to have a library of predicate assert-checking:

```prolog
:- expect_det(p/a).              
:- expect_true(p/a). % This predicate should never be false.
:- expect_number(p/a, 2). % arg2 should be a number
:- expect_grounded(p/a, 2). % arg2 should always be grounded   
....

```

Or better, have these assumptions formally (and optionally) part of the language syntax:

```prolog
p(X:grounded, Y:number) : det, true :-
    ...

```

or, perhaps just:

```prolog
:- constraints( p(grounded, number), [det, true] )
    ...

```

Do such tools exist?

Mercury has something similar, but I think it breaks compatibility with standard Prolog, which is a shame.

---

<div class="post-metadata">

**Author:** ![stuz5000](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/stuz5000/32/940_2.png) [@stuz5000](https://swi-prolog.discourse.group/u/stuz5000)\
**Post date:** [May 29, 2020, 9:02pm UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/15 "2020-05-29T21:02:01Z")

</div>

Oh … similar thoughts here.

> [@Types with SWI-Prolog](https://swi-prolog.discourse.group/t/types-with-swi-prolog/1341/33):
>
> I’ve done further experiments and it seems this is a rather effective way to test that determinism expectations are not violated (of course having an exhaustive testsuite). My remark is that, although to use predicate wrapping is a nice general solution and very useful for debugging complex conditions, I don’t think this it is the right tool for this kind of tracing due to being too much heavyweight. Something integrated with execution (like trace/0 and spy/2) seems a more reasonable choice s…

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [May 29, 2020, 9:18pm UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/16 "2020-05-29T21:18:51Z")

</div>

I’ve opened an issue on rdet’s github repository: [https://github.com/rla/rdet/issues/9](https://github.com/rla/rdet/issues/9)  
Don’t know when I’ll get around to it (it’s not hard, but will take a bit of time).

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [May 31, 2020, 7:01am UTC](https://swi-prolog.discourse.group/t/how-to-find-unexpected-choicepoints/2423/17 "2020-05-31T07:01:41Z")

</div>

> [@peter.ludemann](#):
>
> [BTW, is the cut in your `goal_is_det/1` needed?]

I think it is needed to get rid of the unexpected choice point.

This predicate, exactly as it is defined, was provided on the old mailing list by Jan W. It was because I asked how to do the following (from memory!):

> How do I notice that there is a choice point in my program that I did not put there myself?

I can no longer easily find the original thread.

As already discussed, this is for writing code that is deterministic in nature and does not take advantage of backtracking, multiple solutions and so on. You could call it “writing regular procedures with standard Prolog”. With such code, a choice point means (to me) that I made a mistake somewhere.

You can think of it as a crutch that I need until I learn to not make such errors in the first place.
