Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dealing with complicated prolog loops

I am using Prolog to encode some fairly complicated rules in a project of mine. There is a lot of recursion, including mutual recursion. Part of the rules look something like this:

pred1(X) :- ...
pred1(X) :- someguard(X), pred2(X).

pred2(X) :- ...
pred2(X) :- othercondition(X), pred1(X).

There is a fairly obvious infinite loop between pred1 and pred2. Unfortunately, the interaction between these predicates is very complicated and difficult to isolate. I was able to eliminate the infinite loop in this instance by passing around a list of objects that have been passed to pred1, but this is extremely unwieldy! In fact, it largely defeats the purpose of using Prolog in this application.

How can I make Prolog avoid infinite loops? For example, if in the course of proving pred1(foo) it tries to prove pred1(foo) as a sub-goal, fail and backtrack.

Is it possible to do this with meta-interpreters?

like image 898
Ed McMan Avatar asked Nov 06 '15 15:11

Ed McMan


2 Answers

Yes, you can use meta-interpreters for this purpose, as mat suggests. But for the normal use case, that is going far beyond the regular effort.

What you may consider instead is to separate the looping functionality from your actual logic using higher-order predicates. That is a very safe way to go — SWI even checks if all the uses have a corresponding definition. This checking is either invoked when typing make. or check.

As an example, consider closure0/3 and path/4 which both handle loop checks "once and forever".

like image 88
false Avatar answered Nov 13 '22 02:11

false


One feature that is available in some Prolog systems and that may help you to solve such issues is called tabling. See for example the related question and prolog-tabling.

If tabling is not available, then yes, meta-interpreters can definitely help a lot with this. For example, you can change the executation strategy etc. with a meta-interpreter.

In SWI-Prolog, also check out call_with_inference_limit/3 to robustly limit the execution, independent of CPU type and system load.

Related and also useful are termination analyzers like cTI: They allow you to statically derive termination conditions.

like image 3
mat Avatar answered Nov 13 '22 01:11

mat