2013-06-13 3 views
1

Я пытаюсь создать предикат, который будет генерировать все возможные вычисления сложного термина с числами, например. assign_distinct_values([A-B], E). должно дать 99 результатов.Назначение различных чисел переменным в терминах

Однако, я не могу найти недетерминизм в моем текущем усилии:

assign_distinct_values(E, A) :- 
     term_variables(E, V), 
     assign_distinct_values(E, V, [0,1,2,3,4,5,6,7,8,9], A). 

assign_distinct_values(E, [], [], E). 
assign_distinct_values(E, [], _, E). 
assign_distinct_values(E, V, N, A) :- 
     select(Num, N, N2), 
     select(Var, V, V2), 
     Var is Num, 
     assign_distinct_values(E, V2, N2, A). 

, который генерирует симметричный результат с дубликатами, как:

  • 1-0
  • 0-1
  • 0-1
  • 1-0

ответ

2

Сначала рассмотрит использование более содержательное соглашения об именовании: Я рекомендую присоединени «с» к именам переменных, которые обозначают списки, и нумерацию их более систематически (начиная с 0), и используя более декларативный и значимое имя предиката:

with_distinct_integers(E0, E) :- 
     term_variables(E0, Vs), 
     with_distinct_integers(E0, Vs, [0,1,2,3,4,5,6,7,8,9], E). 

with_distinct_integers(E, [], [], E). 
with_distinct_integers(E, [], _, E). 
with_distinct_integers(E0, Vs0, Ns0, E) :- 
     select(Num, Ns0, Ns), 
     select(Var, Vs0, Vs), 
     Var is Num, 
     with_distinct_integers(E0, Vs, Ns, E). 

Сосредоточение на with_distinct_integers/4 Сейчас. Вы видите, что первое предложение добавляется вторым, поэтому вы можете опустить первое предложение без потери решений. Переменная Var только используется, чтобы объединить его с Num, так что вы можете использовать одну переменную сразу:

with_distinct_integers(E, [], _, E). 
with_distinct_integers(E0, Vs0, Ns0, E) :- 
     select(Num, Ns0, Ns), 
     select(Num, Vs0, Vs), 
     with_distinct_integers(E0, Vs, Ns, E). 

Вы все еще найти непреднамеренные дублирующие решения этой упрощенной версии, и я оставляю его в качестве легкого упражнения, чтобы найти вне зависимости от причины:

?- with_distinct_integers(X-Y, [X,Y], [0,1], A). 
..., A = 0-1 ; 
..., A = 1-0 ; 
..., A = 1-0 ; 
..., A = 0-1 ; 
false. 

Подсказка: просто рассудительно по упрощенному определению. Продолжая упрощение: зачем проходить первоначальный термин, когда у вас уже есть все, что вам нужно, т. Е. Его переменные, доступные? Рассмотрим:

with_distinct_integers(E) :- 
     term_variables(E, Vs), 
     numlist(0, 9, Ns), 
     with_distinct_integers(Vs, Ns). 

with_distinct_integers([], _). 
with_distinct_integers([V|Vs], Ns0) :- 
     select(V, Ns0, Ns), 
     with_distinct_integers(Vs, Ns). 

Пример запроса, считая все решения:

?- findall(., with_distinct_integers([X-Y]), Ls), length(Ls, L). 
Ls = ['.', '.', '.', '.', '.', '.', '.', '.', '.'|...], 
L = 90. 

сюрприз на стороне: есть только 90 решений, а не 99.

Также рекомендуется использовать конечные ограничения домена, которые являются отношения над целыми числами, которые позволяют легко сформулировать такие задачи:

:- use_module(library(clpfd)). 

with_distinct_integers(E) :- 
     term_variables(E, Vs), 
     Vs ins 0..9, 
     all_different(Vs), 
     label(Vs). 

Пример запроса:

?- with_distinct_integers(X-Y). 
X = 0, 
Y = 1 ; 
X = 0, 
Y = 2 ; 
X = 0, 
Y = 3 . 
+0

Отличный anwser, спасибо за объяснения, не используя cplfd. – vvondra

2

L будучи в списке значений и Е, А выходные переменные

assign_distinct_values(E, A, L) :- 
    member(E,L), 
    delete(L,E,L1), 
    member(A,L1). 

использованием прологов предиката довольно быстро. member(X,L) проверяет, находится ли X в L, если это так, мы создаем новый список L1, не содержащий X, с delete(L,X,L1) и повторите проверку для второго элемента таким же образом.

Другой вариант:

assign_distinct_values(E, A) :- 
    L = [0,1,2,3,4,5,6,7,8,9], 
    member(E,L), 
    delete(L,E,L1), 
    member(A,L1). 

ли работа? У меня нет пролога, установленного на моей машине.

С уважением

+0

Это работает только для очень специального случая, что данный термин * есть * единственная переменная. Но в случае использования OP термин может фактически содержать * несколько переменных, соответствующих, например, запросу '? - assign_distinct_values ​​(X-Y, E, [0,1]).' С вашим определением. – mat

Смежные вопросы