3

I am trying to solve a scheduling problem by using SWI Prolog CLP(FD). When trying to solve larger problems I am applying more advanced labeling strategies, and here it would be beneficial to better understand at what point a program is failing and backtracking. Thus, I like to record what variable-bindings cause a fail and using this information to better adapt my labeling heuristic.
In order to illustrate I have generated an example. I generated a predicate that binds a list of Variables to a sequence of values. I would like to know which part of the sequence makes the solution to become invalid and record these variables in the third argument of the predicate.

vars_assign_fail(_, [], []).
vars_assign_fail([S|Vs], [S|Ss], Fs ) :-
    !,
    vars_assign_fail(Vs, Ss, Fs).
vars_assign_fail([_|Vs], [S|Ss], [S|Fs]) :-
    vars_assign_fail(Vs, Ss, Fs).

I can now test this predicate, using only very simple constraints.

?- length(Vs, 6), As=[1, 2, 6, 9, 11, 3], Vs ins 1..5\/8..22, chain(Vs, #<), vars_assign_fail(Vs, As, Fs).
Vs = [1, 2, _51574, 9, 11, _51592],
As = [1, 2, 6, 9, 11, 3],
Fs = [6, 3],
_51574 in 3..5\/8,
_51592 in 12..22.

It tells me that the values 6 and 3 issue a failure in this program. So I want to use this information to modify my test sequence, making use of a finite number of alternative values. In the end I would like to reach something like the following:

solution_valueSeq_alternatives(Vs, Seq, []) :-
    !,
    fail.
solution_valueSeq_alternatives(Vs, Seq, Alt) :-
    vars_assign_fail(Vs, Seq, []).
solution_valueSeq_alternatives(Vs, Seq, [A|Alt]) :-
    vars_assign_fail(Vs, Seq, [F|Fs]),
    sequence_fail_alternative_rearrange(Seq, [F|Fs], A, Reseq),
    solution_valueSeq_alternatives(Vs, Reseq, Alt). 

The problem is that in the third clause vars_assign_fail already partially binds the values of Seq to Vs. I, however, would like to "undo" this (=backtrack) and only keep the information on the bindings that failed (F|Fs). This information is in the predicate sequence_fail_alternative_rearrange consumed in order to create a new sequence with the input of alternative values and the "test" is run again until a valid solution is found - or alternatively the whole iteration fails when running out the list of alternatives.

Can anybody give me advice on how to best implement this in Prolog? Is there a possibility to unbind the variables in Vs again or to only tentatively execute vars_assign_fail? What solution would you recommend?

peter.cyc
  • 1,763
  • 1
  • 12
  • 19

1 Answers1

2

Hint: The not predicate can be applied twice (double negation), you are only interested in whether Goal will succeed or fail and that any bindings shall be discarded. Check Why double negation doesn't bind in Prolog. Use this in your second clause of vars_assign_fail/3, something like:

vars_assign_fail(_, [], []).
vars_assign_fail([V|Vs], [S|Ss], Fs ) :-
    \+ \+ V=S, 
    !,
    vars_assign_fail(Vs, Ss, Fs).
vars_assign_fail([_|Vs], [S|Ss], [S|Fs]) :-
    vars_assign_fail(Vs, Ss, Fs).
peter.cyc
  • 1,763
  • 1
  • 12
  • 19