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