Re: clpfd constraints not taking effect
Markus Triska <[email protected]>
| Newsgroups | gmane.comp.ai.prolog.swi |
|---|---|
| Message-ID | <[email protected]> |
Hi James, James Hogan <[email protected]> writes: > Renaming the "chron-bible" directory to just "bible" (or changing the > incorrect path in src/wrapper.pl to '../../chron-bible/bible') should > make it work. 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). Here, there is not even a functor which can distinguish the cases. 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. 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