Как сортировать вывод в Prolog?

У меня есть следующий предикат:

soln(L,M,O,R,S,V) :-
    permutation([L,M,O,R,S,V],[1,2,3,4,5,6]),
    R=\=S+1,
    R=\=S-1,
    M=:=L+1,
    O>M,
    O<S.

Когда я вызываю его из REPL, он выводит правильные ответы:

?- soln(L,M,O,R,S,V).
L = 1,
M = 2,
O = 3,
R = 4,
S = 6,
V = 5 ;
L = 1,
M = 2,
O = 3,
R = 6,
S = 4,
V = 5 .

Однако более полезным для меня был бы вывод, где переменные отсортированы по их значению; чтобы использовать предыдущий пример, что-то вроде [L,M,O,R,V,S], [L,M,O,S,V,R], ... было бы идеальным.

Я хотел бы иметь возможность делать это как в REPL, так и в автономном скрипте.


person Brennan Vincent    schedule 22.01.2017    source источник


Ответы (1)


Если вы хотите отсортировать имена в соответствии с их значениями, вы должны отслеживать связь между переменными и их именами.

Это связано с тем, что имена переменных, которые вы видите в исходном коде, недоступны в программе Prolog, поэтому вы должны отслеживать имена таким образом, чтобы они были доступны в Prolog.

Один из способов сделать это — отслеживать список пар вида Variable-Name. Таким образом, когда переменная связана со значением, вы все равно знаете ее предполагаемое имя.

Поэтому я предлагаю следующую небольшую переписку:

:- use_module(library(clpfd)).

solution(Pairs) :-
        Vs = [L,M,O,R,S,_V],
        Names = [l,m,o,r,s,v],
        pairs_keys_values(Pairs, Vs, Names),
        R #\= S+1,
        R #\= S-1,
        M #= L+1,
        O #> M,
        O #< S,
        Vs ins 1..6.

Обратите внимание, что теперь я использую атомы l, m, o и т. д. для обозначения имен переменных, а теперь рассуждаю о парах. . Кроме того, я позволил себе выразить все это с помощью ограничений, поэтому мы выигрываем от распространения ограничений вместо того, чтобы пробовать каждую перестановку. Используя ограничения, механизм Prolog может сокращать значительную часть пространства поиска, даже не пытаясь это сделать. Я использую _V для обозначения переменной V, потому что эта переменная больше нигде не упоминается, и поэтому использование V приведет к одноэлементному предупреждению.

Мы уже можем попробовать:

?- solution(Pairs),
   pairs_keys_values(Pairs, Vs, Names),
   label(Vs).
Pairs = [1-l, 2-m, 3-o, 1-r, 4-s, 1-v],
Vs = [1, 2, 3, 1, 4, 1],
Names = [l, m, o, r, s, v] ;
Pairs = [1-l, 2-m, 3-o, 1-r, 4-s, 2-v],
Vs = [1, 2, 3, 1, 4, 2],
Names = [l, m, o, r, s, v] ;
Pairs = [1-l, 2-m, 3-o, 1-r, 4-s, 3-v],
Vs = [1, 2, 3, 1, 4, 3],
Names = [l, m, o, r, s, v] ;
etc.

Теперь, чтобы сортировать имена в соответствии со значениями этих переменных, используйте предикат ISO keysort/2, который сортирует пары в соответствии с их ключами, т. е. их первым компонентом:

?- solution(Pairs0),
   pairs_keys_values(Pairs0, Vs0, Names0),
   label(Vs0),
   keysort(Pairs0, Pairs),
   pairs_values(Pairs, Names).
Pairs0 = [1-l, 2-m, 3-o, 1-r, 4-s, 1-v],
Vs0 = [1, 2, 3, 1, 4, 1],
Names0 = [l, m, o, r, s, v],
Pairs = [1-l, 1-r, 1-v, 2-m, 3-o, 4-s],
Names = [l, r, v, m, o, s] ;
Pairs0 = [1-l, 2-m, 3-o, 1-r, 4-s, 2-v],
Vs0 = [1, 2, 3, 1, 4, 2],
Names0 = [l, m, o, r, s, v],
Pairs = [1-l, 1-r, 2-m, 2-v, 3-o, 4-s],
Names = [l, r, m, v, o, s] ;
Pairs0 = [1-l, 2-m, 3-o, 1-r, 4-s, 3-v],
Vs0 = [1, 2, 3, 1, 4, 3],
Names0 = [l, m, o, r, s, v],
Pairs = [1-l, 1-r, 2-m, 3-o, 3-v, 4-s],
Names = [l, r, m, o, v, s] ;
Pairs0 = [1-l, 2-m, 3-o, 1-r, 4-s, 4-v],
Vs0 = [1, 2, 3, 1, 4, 4],
Names0 = [l, m, o, r, s, v],
Pairs = [1-l, 1-r, 2-m, 3-o, 4-s, 4-v],
Names = [l, r, m, o, s, v] ;
etc.
person mat    schedule 22.01.2017