1

Using a findall in Prolog how can I perform operations inside the goal without affecting backtracking?

The following example explains what I'm trying to achieve:

value('M1', 11, 3).
value('M2', 11, 3).

connection('M1',1, 'A', 'B').
connection('M1',1, 'B', 'C').
connection('M1',2, 'C', 'D').
connection('M1',2, 'D', 'E').
connection('M2',1, 'D', 'F').

run :- bbR('C',[(0,'X',['A'])],_,_).

run2 :- bbR2('C',[(0,['A'])],_,_).

bbR(Destination,[(Cost,_,[Destination|T])|_],Result,Cost):-
   reverse([Destination|T],Result).
bbR(Destination,[(Cost,M_1,[H|T])|Rest],Result,CostSol):-
   write('----'), nl,
   findall( (C, M, [X,H|T]),
            (  Destination\==H,
               connection(M, CX, H, X),
               not(member(X,[H|T])),
               sumValue(M, M_1, F),
               C is CX+Cost+F,
               debug_t(H, X, C, F, M)
            ),
            New),
   append(New,Rest,All),
   sort(All,LS),
   bbR(Destination,LS,Result,CostSol).

sumValue(M, M_1, F):-M_1\==M,value(M, 11, F);F is 0.

debug_t(H, X, C, F, M):-
   write('<'),write(H),
   write('> to <'),write(X),
   write('> @ '), write(M),
   write('> total='),write(C),
   write(' e freq='), write(F),
   nl.

bbR2(Destino,[(Cost,[Destino|T])|_],Result,Cost):-
   reverse([Destino|T],Result).
bbR2(Destino,[(Cost,[H|T])|Rest],Result,CostSol):-
   write('----'), nl,
   findall((C,[X,H|T]),
           (  Destino\==H,
              connection(M, CX, H, X),
              \+ member(X,[H|T]),
              C is CX+Cost,
              debug_t(H, X, C, 0, M)
           ),
           New),
   append(New,Rest,All),
   sort(All,LS),
   bbR2(Destino,LS,Result,CostSol).

The problem here is, when I run "run.", it prints:

    <A> to <B> @ M1> total=4 e freq=3
    <A> to <B> @ M1> total=1 e freq=0

Whereas if I run "run2." (which is the same code without the call to sumValue and the "+ F") it only prints

    <A> to <B> @ M1> total=1 e freq=0

From my debugging it seems the problem is when findall finishes the first goal and backtracks, the sumValue affects it's behavior.

So my main question is How to sum values (from another predicate) to the variable "C" under certain conditions (in this case, when "M_1" is different to "M") without affecting the findall backtracking.

I have been trying all day to find a way around this, I already tried using "!" but to no avail.

wyldkat
  • 13
  • 4

1 Answers1

0

The reason you get different behaviours when querying run. and run2. is because the goal sumValue('M1', _, F) is being satisfied twice:

?- sumValue('M1', _, F).
F = 3 ;
F = 0.

I would also recommend you to use format/2 instead of all those write/1 predicates. It helps for code readability.

debug_t(H, X, C, F, M):-
    format("<~w> to <~w> @ ~w> total=~w e freq=~w~n", [H, X, M, C, F]).
Tudor Berariu
  • 4,910
  • 2
  • 18
  • 29
  • Thanks. I've changed the predicate to: sumValue(M, M, 0):-!. sumValue(M, _, F):-value(M, 11, F). And it works just fine... I have one question tho, why is the :-! im sumValue(M, M, 0) necessary? – wyldkat Jan 08 '15 at 20:18
  • The cut operator prevents using the second rule for `sumValue/3` if the first argument unified with the second and the third argument unified with zero. In other words: if the first rule matches, the second won't be used. If the second rule is being used it means the first rule failed to unify. The result is that you can satisfy a `sumValue/3` goal at most once. – Tudor Berariu Jan 08 '15 at 20:23