Search code examples
recursionprologbacktrackingprolog-findall

Prolog - Operation inside findall


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.


Solution

  • 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]).