% maximize(G, S, Min, Max).
% Succeeds if S is the maximum value for G to succeed, when S is between Min and Max.

maximize(G, S, Min, Max) :-
   domain(I, Min, Max + 1),
   domain(Best, Min, Max),
   domain(Fail, 0, 1),
   domain(A, 0, 1),
   domain(B, 0, 1),
   domain(C, 0, 1),
   (Fail = 0 -> A != B /\ B != C /\ A != C),
   store("bb_best", [Min, 0]),
   labeling(I, Min, Max + 1),
   retrieve("bb_best", [Best, Fail]),
   (
      Fail = 0,
      store("bb_best", [Best, 1]),
      S > Best,
      G,
      store("bb_best", [S, 0]),
      labeling(A, 0, 1),
      labeling(B, 0, 1)
   ;
      Fail = 1,
      I = Max + 1,
      S = Best,
      G
   ).

% minimize(G, S, Min, Max).
% Succeeds if S is the minimum value for G to succeed, when S is between Min and Max.

minimize(G, S, Min, Max) :-
   domain(Dual, Min, Max),
   Dual = Max - S + Min,
   maximize(G, Dual, Min, Max).