Prolog successor notation yields incomplete result and infinite loop
Asked Answered
P

2

42

I start to learn Prolog and first learnt about the successor notation.

And this is where I find out about writing Peano axioms in Prolog.

See page 12 of the PDF:

sum(0, M, M).
sum(s(N), M, s(K)) :-
    sum(N,M,K).

prod(0,M,0).
prod(s(N), M, P) :-
    prod(N,M,K),
    sum(K,M,P).

I put the multiplication rules into Prolog. Then I do the query:

?- prod(X,Y,s(s(s(s(s(s(0))))))).

Which means finding the factor of 6 basically.

Here are the results.

X = s(0),
Y = s(s(s(s(s(s(0)))))) ? ;
X = s(s(0)),
Y = s(s(s(0))) ? ;
X = s(s(s(0))),
Y = s(s(0)) ? ;
infinite loop

This result has two problems:

  1. Not all results are shown, note that the result X=6,Y=1 is missing.
  2. It does not stop unless I Ctrl+C then choose abort.

So... my questions are:

  1. WHY is that? I tried switching "prod" and "sum" around. The resulting code gives me all results. And again, WHY is that? It still dead-loops though.
  2. HOW to resolve that?

I read the other answer on infinite loop. But I'd appreciate someone answer basing on this scenario. It greatly helps me.

Portemonnaie answered 13/4, 2012 at 11:3 Comment(1)
After comparing the tag wikis, non-termination seems a much better fit. In fact, judging from the tag wikis, almost all instances where we currently use infinite-loop together with prolog should actually be tagged instead or in addition with non-termination. What is the best place to discuss such tagging best practices? Personally, I prefer non-termination, at least in addition to infinite-loop.Slender
G
36

If you want to study termination properties in depth, programs using are an ideal study object: You know a priori what they should describe, so you can concentrate on the more technical details. You will need to understand several notions.

Universal termination

The easiest way to explain it, is to consider Goal, false. This terminates iff Goal terminates universally. That is: Looking at tracers is the most ineffective way - they will show you only a single execution path. But you need to understand all of them at once! Also never look at answers when you want universal termination, they will only distract you. You have seen it above: You got three neat and correct answers, only then your program loops. So better "turn off" answers with false. This removes all distraction.

Failure slice

The next notion you need is that of a failure slice. Take a pure monotonic logic program and throw in some goals false. If the resulting failure slice does not terminate (universally), also the original program won't. In your exemple, consider:

prod(0,M,0) :- false.
prod(s(N), M, P) :-
    prod(N,M,K), false,
    sum(K,M,P).

These false goals help to remove irrelevant adornments in your program: The remaining part shows you clearly, why prod(X,Y,s(s(s(s(s(s(0))))))). does not terminate. It does not terminate, because that fragment does not care about P at all! You are hoping that the third argument will help to make prod/3 terminate, but the fragment shows you it is all in vain, since P does not occur in any goal. No need for chatty tracers.

Often it is not so easy to find minimal failure slices. But once you found one, it is next to trivial to determine its termination or rather non-termination properties. After some time you can use your intuition to imagine a slice, and then you can use your reason to check if that slice is of relevance or not.

What is so remarkable about the notion of a failure slice is this: If you want to improve the program, you have to modify your program in the part visible in above fragment! As long as you do not change it, the problem will persist. A failure slice is thus a very relevant part of your program.

Termination inference

That is the final thing you need: A termination inferencer (or analyzer) like cTI will help you to identify the termination condition rapidly. Look at the inferred termination conditions of prod/3 and the improved prod2/3 here!


Edit: And since this was a homework question I have not posted the final solution. But to make it clear, here are the termination conditions obtained so far:

    prod(A,B,C)terminates_if b(A),b(B).
    prod2(A,B,C)terminates_if b(A),b(B);b(A),b(C).

So the new prod2/3 is strictly better than the original program!

Now, it is up to you to find the final program. Its termination condition is:

   prod3(A,B,C)terminates_if b(A),b(B);b(C).

To start with, try to find the failure slice for prod2(A,B,s(s(s(s(s(s(0)))))))! We expect it to terminate, but it still does not. So take the program and add manuallyfalse goals! The remaining part will show you the key!

As a final hint: You need to add one extra goal and one fact.


Edit: Upon request, here is the failure slice for prod2(A,B,s(s(s(s(s(s(0))))))):

prod2(0,_,0) :- false.
prod2(s(N), M, P) :-
   sum(M, K, P),
   prod2(N,M,K), false.

sum(0, M, M).
sum(s(N), M, s(K)) :- false,
    sum(N,M,K).

Please note the significantly simplified definition of sum/3. It only says: 0 plus anything is anything. No more. As a consequence even the more specialized prod2(A,0,s(s(s(s(s(s(0))))))) will loop whileprod2(0,X,Y) elegantly terminates ...

Grader answered 13/4, 2012 at 12:51 Comment(27)
By failure slice, it is like negating all the conditions in the rules? And then we do a query like normal? i.e. prod(X,Y,s(s(s(s(s(s(0)))))))?Portemonnaie
but prod2(X,Y,s(0)) (or any other value) doesn't terminate either. It's an improvement?Cool
@Felastine: You add further goals false/0 somewhere. So you are not negating a condition. Negating, that would be e.g. dif(X,a) in place of X = a.Grader
@chac: Yes. Please study the termination conditions inferred by cTI - see last link.Grader
Really great answer. And Localizing and explaining reasons for non-terminating logic programs with failure-slices is something I absolutely need to grasp.Cool
@j4nbur53: You are talking about existential termination. This notion is very rarely used since it is very brittle. In particular, the conjunction of two existentially terminating goals is not necessarily terminating. However, the conjunction of two universally goals is terminating.Grader
@j4nbur53: Please refer to Plümer, Termination Proofs for Logic Programs, LNAI 446, for the observation about termination of the conjunction. It seems your terminology differs a lotGrader
@j4nbur53: Please note that the terminology of universal and existential termination also corresponds to Marchiori 1996.Grader
Marchiori introduces k-termination, he sets 1-termination=existential terminaton, omega-termination=Example 4.3 and omega+1-termination=universal temination. As an end-user I am less interested in universal termination and more in Example 4.3. Can failure-slices help here?Disciplinarian
@j4nbur53: Please note that my answer is about universal termination only. I am rather skeptical that failure-slices can help with m-termination for m in 1..ωGrader
But the other answer still has the clauses that you striked out. So how can it be the correct program?Salazar
This is the other answer. It's the only place where prod3/3 is defined.Grader
Yes I was referring to this answer. And it defines prod3(0, _, 0). and sum(s(N), M, s(K)) :- sum(N, M, K)., while in your answer you strike out prod2(0, _, 0). and sum(s(N), M, s(K)) :- sum(N, M, K)., meaning that they are useless clauses. And you say: ‘As a final hint: You need to add one extra goal and one fact.’ So I assumed the correct answer should have different clauses that the ones you striked out.Salazar
useless clauses they are in the context of non-termination. That's the key idea in failure slices. But they still have some meaning; and there they are not useless.Grader
In other words, you mean that the striked out clauses are useful only in the context of termination as they are evaluated, while they are useless in the context of non-termination as they are never reached.Salazar
Look, you cannot expect that you do not by yourself read about failure-slices and now get spoon fed every tiny detail. There are tons, well more than one hundred of related examples here on SO. And, then there is the literature cited above, too. You really need to put an effort on your side first.Grader
I am a beginner in logic programming (taking this online Stanford course) and I am genuinely trying to understand your post. The fact that it does not provide the correct answer and leave it as an exercise to the reader is already hard enough, so if I cannot even ask you questions it is not very motivating. You claim that Capellic gave the correct answer but the cTI report of his program is sum(A,B,C)terminates_if b(A);b(C). and prod3(A,B,C)terminates_if b(A),b(B);b(A),b(C). which is clearly wrong for both rules.Salazar
sum(A,B,C)terminates_if b(A);b(C). is better than what you expected. This is under no circumstance a problem! And for prod3/3 look closely! The systems shows the cases where it is not able to prove termination nor non-termination, Provers are often not as strong as we would like them to be, but cTI at least shows the unresolved cases. And for the exercise to the reader: It is in full source in the other answer with exactly the same name.Grader
@Maggyero: Where does the course demand such programs from you?Grader
To get the expected sum(A,B,C)terminates_if b(A),b(B);b(C). in the cTI report, you simply have to replace sum(N, M, K) with sum(M, N, K) in sum(s(N), M, s(K)) :- sum(N, M, K). i.e. switch N and M. Isn’t it better? This updated sum also updates the cTI report of prod3 to prod3(A,B,C)terminates_if b(A),b(C). However I did not find another correction of prod3 to get the expected prod3(A,B,C)terminates_if b(A),b(B);b(C). advertised in your answer.Salazar
The course demands such programs in exercise 9.4.Salazar
But that exercise is not about Prolog! The syntax is different. There is no & for conjunction etc- number is coincidentally the same name but next isn't known in Prolog at all.Grader
@Grader The teacher uses Epilog, but the translation into Prolog is trivial: next/2 is succ/2 and &/2 is ,/2. And since I did not quickly find an online Epilog interpreter on Google, I used Prolog (more precisely the SWI-Prolog implementation of Prolog, available as SWISH).Salazar
@Grader Chapter 1: ‘Epilog (the language we use in this volume) is closely related to Datalog and Prolog. Their syntaxes are almost identical. And the three languages are nicely ordered in terms of expressiveness - with Datalog being a subset of Prolog and Prolog being a subset of Epilog. For the sake of simplicity, we use the syntax of Epilog throughout this course, and we talk about the Epilog interpreter and compiler. Thus, when we mention Datalog in what follows, we are referring to the Datalog subset of Epilog; and, when we mention Prolog, we are referring to the Prolog subset of Epilog.’Salazar
@Grader So is the rule sum(0, M, M). sum(s(N), M, s(K)) :- sum(M, N, K). better than sum(0, M, M). sum(s(N), M, s(K)) :- sum(N, M, K). since cTI reports sum(A,B,C)terminates_if b(A),b(B);b(C). for the former and sum(A,B,C)terminates_if b(A);b(C). for the latter?Salazar
@Maggyero: This is a question of its own.Grader
@Grader Granted.Salazar
C
17

The first question (WHY) is fairly easy to spot, specially if know about left recursion. sum(A,B,C) binds A and B when C is bound, but the original program prod(A,B,C) doesn't use that bindings, and instead recurse with still A,B unbound.

If we swap sum,prod we get 2 useful bindings from sum for the recursive call:

sum(M, K, P)

Now M is bound, and will be used to terminate the left-recursion. We can swap N and M, because we know that product is commutative.

sum(0, M, M).
sum(s(N), M, s(K)) :-
    sum(N, M, K).

prod3(0, _, 0).
prod3(s(N), M, P) :-
    sum(M, K, P),
    prod3(M, N, K).

Note that if we swap M,K (i.e. sum(K,M,P)), when prod3 is called with P unknown we again have a non terminating loop, but in sum.

?- prod3(X,Y,s(s(s(s(s(s(0))))))).
X = s(s(s(s(s(s(0)))))),
Y = s(0) ;
X = s(s(s(0))),
Y = s(s(0)) ;
X = s(s(0)),
Y = s(s(s(0))) ;
X = s(0),
Y = s(s(s(s(s(s(0)))))) ;
false.

OT I'm perplexed by cTI report: prod3(A,B,C)terminates_if b(A),b(B);b(A),b(C).

Cool answered 18/4, 2012 at 17:20 Comment(3)
concerning cTI: The system tells you that there are 2 unresolved: [prod3(f,b,b),prod3(f,f,b)]. This means that cTI was not able to infer these cases and NTI was not able to prove nontermination. So it is unknown to cTI. See the manualGrader
The cTI report of your program is sum(A,B,C)terminates_if b(A);b(C). and prod3(A,B,C)terminates_if b(A),b(B);b(A),b(C). which is clearly wrong for both rules. I would expect sum(A,B,C)terminates_if b(A),b(B);b(C). and prod3(A,B,C)terminates_if b(A),b(B);b(C).Salazar
@Maggyero: This is a misunderstanding. Look at sum(0, B,C) to see that it is in fact terminating.Grader

© 2022 - 2024 — McMap. All rights reserved.