fd_exactly/3
15/03/08 12:00
Niech X1, X2, ..., Xm będą FD-zmiennymi. Chcemy na zmienne te narzucić warunek, że dokładnie N z nich ma wartość równą K, gdzie N i K są liczbami całkowitymi.
W tym celu możemy użyć w GNU-Prologu predykatu fd_exactly/3, którego pierwszym argumentem jest N, drugim lista zmiennych [X1, X2, ..., Xm] a trzecim wartość K.
Oto prosty przykład, w którym trzy spośród czterech zmiennych o dziedzinach 0..3 ma wartość 1:
| ?- X = [X1, X2, X3, X4], fd_domain(X, 0, 3), fd_exactly(3, X, 1).
X = [_#3(0..3),_#25(0..3),_#47(0..3),_#69(0..3)]
X1 = _#3(0..3)
X2 = _#25(0..3)
X3 = _#47(0..3)
X4 = _#69(0..3)
yes
Jeśli dodatkowo na zmienną X2 narzucimy warunek, że jest ona większa od 1, to system wywnioskuje, że pozostałe zmienne muszą mieć wartość 1:
| ?- X = [X1, X2, X3, X4], fd_domain(X, 0, 3), fd_exactly(3, X, 1), X2 #> 1.
X = [1,_#25(2..3),1,1]
X1 = 1
X2 = _#25(2..3)
X3 = 1
X4 = 1
yes
Częstym błędem jest użycie predykatu fd_exactly/3 z FD-zmienną N lub K zamiast konkretną liczbą całkowitą.
Spróbujmy na cztery zmienne o dziedzinach 0..2 narzucić warunek, że wartość 2 występuje wśród nich o jeden raz więcej niż wartość 1:
| ?- X = [X1, X2, X3, X4], fd_domain(X, 0, 2),
fd_exactly(N1, X, 1), fd_exactly(N2, X, 2), N2 #= N1+1.
uncaught exception: error(instantiation_error,fd_exactly/3)
Zgłoszony wyjątek sygnalizuje, że jeden z argumentów predykatu fd_exactly/3 jest niepoprawnej postaci.
Aby obejść ograniczenia predykatu fd_exactly/3 można zdefiniować własną jego wersję, która buduje listę odpowiednich równań i za pomocą predykatu fd_cardinality/2 narzuca warunek, że dokładnie N z nich jest spełnionych.
my_exactly(N, X, K) :-
rownania(X, K, R),
fd_cardinality(R, N).
rownania([], _, []).
rownania([Xi | L1], K, [Xi #= K | L2]) :-
rownania(L1, K, L2).
Tym razem udaje się narzucić wszystkie warunki:
| ?- X = [X1, X2, X3, X4], fd_domain(X, 0, 2),
my_exactly(N1, X, 1), my_exactly(N2, X, 2), N2 #= N1+1.
N1 = _#91(0..3)
N2 = _#339(1..4)
X = [_#3(0..2),_#25(0..2),_#47(0..2),_#69(0..2)]
X1 = _#3(0..2)
X2 = _#25(0..2)
X3 = _#47(0..2)
X4 = _#69(0..2)
yes
O tym, że warunki zostały dobrze narzucone można przekonać się drukując wszystkie rozwiązania:
| ?- X = [X1, X2, X3, X4], fd_domain(X, 0, 2),
my_exactly(N1, X, 1), my_exactly(N2, X, 2), N2 #= N1+1,
fd_labeling(X), write(X), nl, fail.
[0,0,0,2]
[0,0,2,0]
[0,1,2,2]
[0,2,0,0]
[0,2,1,2]
[0,2,2,1]
[1,0,2,2]
[1,2,0,2]
[1,2,2,0]
[2,0,0,0]
[2,0,1,2]
[2,0,2,1]
[2,1,0,2]
[2,1,2,0]
[2,2,0,1]
[2,2,1,0]
no
Użyty w powyższym przykładzie predykat fd_labeling/1 znajduje wartości zmiennych spełniające wszystkie narzucone warunki, natomiast przy nawrotach spowodowanych predykatem fail/0, znajdowane są kolejne odpowiedzi.
W tym celu możemy użyć w GNU-Prologu predykatu fd_exactly/3, którego pierwszym argumentem jest N, drugim lista zmiennych [X1, X2, ..., Xm] a trzecim wartość K.
Oto prosty przykład, w którym trzy spośród czterech zmiennych o dziedzinach 0..3 ma wartość 1:
| ?- X = [X1, X2, X3, X4], fd_domain(X, 0, 3), fd_exactly(3, X, 1).
X = [_#3(0..3),_#25(0..3),_#47(0..3),_#69(0..3)]
X1 = _#3(0..3)
X2 = _#25(0..3)
X3 = _#47(0..3)
X4 = _#69(0..3)
yes
Jeśli dodatkowo na zmienną X2 narzucimy warunek, że jest ona większa od 1, to system wywnioskuje, że pozostałe zmienne muszą mieć wartość 1:
| ?- X = [X1, X2, X3, X4], fd_domain(X, 0, 3), fd_exactly(3, X, 1), X2 #> 1.
X = [1,_#25(2..3),1,1]
X1 = 1
X2 = _#25(2..3)
X3 = 1
X4 = 1
yes
Częstym błędem jest użycie predykatu fd_exactly/3 z FD-zmienną N lub K zamiast konkretną liczbą całkowitą.
Spróbujmy na cztery zmienne o dziedzinach 0..2 narzucić warunek, że wartość 2 występuje wśród nich o jeden raz więcej niż wartość 1:
| ?- X = [X1, X2, X3, X4], fd_domain(X, 0, 2),
fd_exactly(N1, X, 1), fd_exactly(N2, X, 2), N2 #= N1+1.
uncaught exception: error(instantiation_error,fd_exactly/3)
Zgłoszony wyjątek sygnalizuje, że jeden z argumentów predykatu fd_exactly/3 jest niepoprawnej postaci.
Aby obejść ograniczenia predykatu fd_exactly/3 można zdefiniować własną jego wersję, która buduje listę odpowiednich równań i za pomocą predykatu fd_cardinality/2 narzuca warunek, że dokładnie N z nich jest spełnionych.
my_exactly(N, X, K) :-
rownania(X, K, R),
fd_cardinality(R, N).
rownania([], _, []).
rownania([Xi | L1], K, [Xi #= K | L2]) :-
rownania(L1, K, L2).
Tym razem udaje się narzucić wszystkie warunki:
| ?- X = [X1, X2, X3, X4], fd_domain(X, 0, 2),
my_exactly(N1, X, 1), my_exactly(N2, X, 2), N2 #= N1+1.
N1 = _#91(0..3)
N2 = _#339(1..4)
X = [_#3(0..2),_#25(0..2),_#47(0..2),_#69(0..2)]
X1 = _#3(0..2)
X2 = _#25(0..2)
X3 = _#47(0..2)
X4 = _#69(0..2)
yes
O tym, że warunki zostały dobrze narzucone można przekonać się drukując wszystkie rozwiązania:
| ?- X = [X1, X2, X3, X4], fd_domain(X, 0, 2),
my_exactly(N1, X, 1), my_exactly(N2, X, 2), N2 #= N1+1,
fd_labeling(X), write(X), nl, fail.
[0,0,0,2]
[0,0,2,0]
[0,1,2,2]
[0,2,0,0]
[0,2,1,2]
[0,2,2,1]
[1,0,2,2]
[1,2,0,2]
[1,2,2,0]
[2,0,0,0]
[2,0,1,2]
[2,0,2,1]
[2,1,0,2]
[2,1,2,0]
[2,2,0,1]
[2,2,1,0]
no
Użyty w powyższym przykładzie predykat fd_labeling/1 znajduje wartości zmiennych spełniające wszystkie narzucone warunki, natomiast przy nawrotach spowodowanych predykatem fail/0, znajdowane są kolejne odpowiedzi.