1
spec(comp1, pc, 32).                                      /* Fact  1 */
spec(comp2, mac, 128).                                    /* Fact  2 */
spec(comp3, pc, 64).                                      /* Fact  3 */
runs(pc, movie_edit, 96).                                 /* Fact  4 */
runs(pc, vb, 16).                                         /* Fact  5 */
runs(pc, cpp, 28).                                        /* Fact  6 */
runs(mac, vb, 24).                                        /* Fact  7 */
runs(mac, prolog, 128).                                   /* Fact  8 */
access(judy, comp1).                                      /* Fact  9 */
access(peter, comp3).                                     /* Fact 10 */
access(david, comp1).                                     /* Fact 11 */
access(david, comp2).                                     /* Fact 12 */
can_use(P, SW) :- access(P, Comp), can_run(Comp, SW).     /* Rule  1 */

can_run(Comp, SW) :- spec(Comp, CompType, MemAvail),
                   runs(CompType, SW, MemNeeded),
                   MemAvail >= MemNeeded.               /* Rule   2 */

?- can_use(judy, vb).
?- can_use(david, prolog).

The first goal returns: true, false. Whereas the second one returns only true.
My question is why in the first goal we have that extra information.
I'm using SWI-Prolog 7.6.4 version

false
  • 10,264
  • 13
  • 101
  • 209
Hamza
  • 157
  • 2
  • 12

1 Answers1

1

The reason this happens is because in the former case, there is still "opportunity" for backtracking whereas in the latter, there is no such opportunity.

If we call the goal with the trace, we see:

[trace]  ?- can_use(judy, vb).
   Call: (8) can_use(judy, vb) ? creep
   Call: (9) access(judy, _2968) ? creep
   Exit: (9) access(judy, comp1) ? creep
   Call: (9) can_run(comp1, vb) ? creep
   Call: (10) spec(comp1, _2968, _2970) ? creep
   Exit: (10) spec(comp1, pc, 32) ? creep
   Call: (10) runs(pc, vb, _2970) ? creep
   Exit: (10) runs(pc, vb, 16) ? creep
   Call: (10) 32>=16 ? creep
   Exit: (10) 32>=16 ? creep
   Exit: (9) can_run(comp1, vb) ? creep
   Exit: (8) can_use(judy, vb) ? creep
true ;
   Redo: (10) runs(pc, vb, _2970) ? 

We here thus make a call to runs/3 with runs(pc, vb, MemNeeded) and Prolog finds a first answer with 16. But it sets a backtracking point to look for other runs/3 facts with runs(pc, vb, MemNeeded). Imagine that there is another fact later in the source code, for example runs(pc, vb, 14) at the end, then this can produce another answer.

If we however call the second goal, we see:

[trace]  ?- can_use(david, prolog).
   Call: (8) can_use(david, prolog) ? creep
   Call: (9) access(david, _3726) ? creep
   Exit: (9) access(david, comp1) ? creep
   Call: (9) can_run(comp1, prolog) ? creep
   Call: (10) spec(comp1, _3726, _3728) ? creep
   Exit: (10) spec(comp1, pc, 32) ? creep
   Call: (10) runs(pc, prolog, _3728) ? creep
   Fail: (10) runs(pc, prolog, _3728) ? creep
   Fail: (9) can_run(comp1, prolog) ? creep
   Redo: (9) access(david, _3726) ? creep
   Exit: (9) access(david, comp2) ? creep
   Call: (9) can_run(comp2, prolog) ? creep
   Call: (10) spec(comp2, _3726, _3728) ? creep
   Exit: (10) spec(comp2, mac, 128) ? creep
   Call: (10) runs(mac, prolog, _3728) ? creep
   Exit: (10) runs(mac, prolog, 128) ? creep
   Call: (10) 128>=128 ? creep
   Exit: (10) 128>=128 ? creep
   Exit: (9) can_run(comp2, prolog) ? creep
   Exit: (8) can_use(david, prolog) ? creep
true.

Here we call runs(mac, prolog, MemNeeded)., and this is the last fact of runs/3, hence there is no other possibility to satisfy runs/3 otherwise: since Prolog runs top to bottom, if we have satisfied the last fact/clause, we know that there is no other option.

Since all other calls also take the last predicate as well, or with a different constant as first parameter (SWI-Prolog looks at the first argument when it compiles the source code as an optimization), there are no other backtracking points, and thus there is no way to Redo a certain call.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Thank you for your extensive answer. I just don't get why there isn't other backtracking points, such as : `spec(comp1, _2968, _2970)` – Hamza Dec 02 '18 at 11:28
  • 1
    @Hamza: well that depends a bit on the interpreter. But a lot of interpeters (SWI-Prolog included), look at the first argument, and thus make sure that if the first argument is grounded, it directly finds the correct facts. It thus performs some sort of "indexing" on the first argument. Technically speaking, interpreters could use the same trick on the second argument, a combination of the first and second argument, etc. The question is of course if all that indexing is worth the effort, so iirc, this is only done on the first argument. – Willem Van Onsem Dec 02 '18 at 11:30