Re: clpfd constraints not taking effect

James Hogan <[email protected]>
Newsgroups gmane.comp.ai.prolog.swi
Message-ID <CAAG0J98j3k5RZmKR5aBh1D+QnszKaY3W-zruijW106-fu9qCMw@mail.gmail.com>
Hi Markus,

On 23 August 2013 19:04, Markus Triska <[email protected]> wrote:
> OK, it now runs and I have looked into it. SWI runs out of stack in
> this case because many of your predicates leave unnecessary
> choice-points behind. The fact that you need a !/0 after process_db/2
> already gives a clue that the predicate is intended to be
> deterministic, but the system cannot detect this. Among other things,
> this is because SWI does not (yet) perform deep indexing on predicate
> arguments. You can apply simple changes which let the system detect
> the determinism. For example, consider your apply_preargs/3:
>
>    apply_preargs(_, [], []).
>    apply_preargs(Events, [event_time(Event)|Tail], [Time|RTail]) :-
>           get_event_time(Events, Event, time(Time, raw)),
>           apply_preargs(Events, Tail, RTail).
>    apply_preargs(Events, [pass(Data)|Tail], [Data|RTail]) :-
>           apply_preargs(Events, Tail, RTail).
>
> You can benefit from indexing if you rewrite this for example as:
>
>    apply_preargs(Events, List0, List) :-
>            maplist(apply_prearg(Events), List0, List).
>
>    apply_prearg(Events, event_time(Event), Time) :-
>            get_event_time(Events, Event, time(Time, raw)).
>    apply_prearg(_, pass(Data), Data).
>
> Notice that event_time/1 and pass/1 are now the outermost terms in the
> auxiliary predicate's second argument (instead of being wrapped inside a
> list) and can hence be distinguished by indexing.
>
> As another example for non-determinism, consider your expand_event/1:
>
>    expand_event(Simple, Simple) :-
>            event(Simple).
>    expand_event(Simple, Raw) :-
>            event_simplifier(Middle, Simple),
>            expand_event(Middle, Raw).

(this example is one that particularly bothered me as it felt a bit
vulnerable to problems).

>
> Here, there is not even a functor which can distinguish the cases.

Ah, I think I get it, so in the apply_preargs example, SWI's shallow
look at apply_preargs sees the latter two functors as taking the same
argument types, so it has to remember it in case the first fails or
other solutions required.

> Since in your case, the first argument is always instantiated when the
> predicate is called, you can rewrite this for example as:
>
>    event_expansion(Event0, Event) :-
>            (   event(Event0) -> Event = Event0
>            ;   event_simplifier(Event1, Event0),
>                event_expansion(Event1, Event)
>            ).
>
> to obtain a deterministic predicate. A cleaner solution is of course
> to use two functors to distinguish the two cases:
>
>    event_expansion(simple(Simple), Simple).
>    event_expansion(complex(Complex), Expansion) :- ...
>
> This version can, in addition to being deterministic when the first
> argument is instantiated, also *still* be used in all directions.
>
> Other examples of probably unintended non-determinism are
> get_event_time/1 and person/1.
>
> You can use SWI-Prolog's graphical tracer to see which predicates
> still leave choice-points behind:
>
>    ?- gtrace, process_db(creation, Events).
>
> Step through the goals (SPACE, "s" etc.) and check in the graphical
> call tree where you leave choice-points behind.
>
> SWI-Prolog's top-level also is of great help, for example:
>
>    ?- person(enosh).
>    true ;
>    true ;
>    false.

yes, I've been trying to get rid of these cases, especially the final
false (which now makes much more sense).

gtrace is neat! I wasn't aware of the graphical version, and always
found the text one a bit confusing.

>
> You know that everything is deterministic when
>
>    ?- process_db(creation, Events).
>
> yields a single answer and does not prompt you for more. At that
> point, you do not need the !/0 in your sample queries any longer, and
> you will also benefit from CLP(FD)'s improved propagation that
> triggered this thread and which I will definitely re-enable in some
> form after I have done more benchmarks. Your program will thus also
> likely become more efficient independently of the CLP(FD) change.
>
> All the best,
> Markus

Thanks so much for taking the time to analyse and for the great tips.

Cheers
James Hogan
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.