Подтвердить что ты не робот

Перестановка переменных_names

Как написать стандартным образом avs_term_rearranged(AVs, T, AVsR) с заданными AVs и T такими, что AVsR является перестановкой AVs с элементами, расположенными в том же порядке, что и их переменные, встречающиеся слева направо - порядок в T.

AVs - это список элементов формы A = V, где A - это атом, обозначающий имя переменной типа 'X' и V - соответствующая переменная. Такие списки создаются с помощью read_term/2,3 с опцией чтения variable_names/1 (7.10.3). Кроме того, точный порядок элементов не определен.

| ?- read_term(T,[variable_names(AVs)]).
A+B+A+_+C.

AVs = ['A'=A,'B'=B,'C'=C]
T = A+B+A+_+C

T - это термин, содержащий все переменные AVs плюс еще несколько.

Заметим, что в стандартной программе соответствия нельзя полагаться на термин порядок для переменных (7.2.1):

7.2.1 Переменная

Если X и Y являются переменными, которые не идентичны, то X term_precedes Y должен быть зависимым от реализации, за исключением того, что во время создания отсортированного списка (7.1.6.5, 8.10.3.1 j) порядок должен оставаться постоянным.

ПРИМЕЧАНИЕ — Если X и Y являются анонимными переменными, то они не являются идентичными терминами (см. 6.1.2 а).

Рассмотрим в качестве примера из 8.4.3.4:

sort([f(U),U,U,f(V),f(U),V],L).
   Succeeds, unifying L with [U,V,f(U),f(V)] or
   [V,U,f(V),f(U)].
   [The solution is implementation dependent.]

Таким образом, существует два возможных способа работы sort/2, и нельзя даже рассчитывать на успех:

sort([f(U),U,U,f(V),f(U),V],L), sort(L, K), L == K.

В качестве примера:

?- avs_term_rearranged(['A'=A,'B'=B,'C'=C], A+C+F+B, AVsR).
   AVsR = ['A'=A,'C'=C,'B'=B].
4b9b3361

Ответ 1

avs_term_rearranged(AVs, T, AVsR) :-
    term_variables(T, Vs),
    copy_term(Vs+AVs, Vs1+AVs1),
    bind_names(AVs1),
    build_vn_list(Vs, Vs1, AVsR).

bind_names([]).
bind_names([N=V|AVs]) :-
    N = V,
    bind_names(AVs).

build_vn_list([], [], []).
build_vn_list([V|Vs],[N|Ns],NVs) :-
    ( atom(N) ->
      NVs = [N=V|NVs1]
    ; var(N) ->
      NVs = NVs1
    ),
    build_vn_list(Vs, Ns, NVs1).

Ответ 2

Используйте term_variables/2 on T, чтобы получить список Xs с переменными в желаемом порядке. Затем создайте список с элементами AVs, но в этом порядке.

avs_term_rearranged(AVs, T, AVRs) :-
    term_variables(T, Xs),
    pick_in_order(AVs, Xs, AVRs).

pick_in_order([], [], []).
pick_in_order(AVs, [X|Xs], AVRs) :-
    ( pick(AVs, X, AV, AVs1) ->
        AVRs = [AV|AVRs1],
        pick_in_order(AVs1, Xs, AVRs1)
    ;
        pick_in_order(AVs, Xs, AVRs)
    ).

pick([AV|AVs], X, AX, DAVs) :-
    (_=V) = AV,
    ( V==X ->
        AX = AV,
        DAVs = AVs
    ;
        DAVs = [AV|DAVs1],
        pick(AVs, X, AX, DAVs1)
    ).

Примечания:

  • это квадратично, потому что pick/4 является линейным
  • term_variables/2 не является строго необходимым, вы можете напрямую пересекать T

Ответ 3

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

Как и раньше, мы в основном переставляем список AVs таким образом, чтобы его элементы имели тот же порядок, что и переменные в списке Xs (полученные из term_variables/2). Новая идея здесь состоит в том, чтобы сначала вычислить (базовое) описание требуемой перестановки (APs), а затем построить подстановку AV с использованием этого описания.

avs_term_rearranged(AVs, T, AVRs) :-
    term_variables(T, Xs),
    copy_term(AVs-Xs, APs-Ps),
    ints(Ps, 0, N),
    functor(Array, a, N),
    distribute(AVs, APs, Array),
    gather(1, N, Array, AVRs).

ints([], N, N).
ints([I|Is], I0, N) :- I is I0+1, ints(Is, I, N).

distribute([], [], _).
distribute([AV|AVs], [_=P|APs], Array) :-
    nonvar(P),
    arg(P, Array, AV),
    distribute(AVs, APs, Array).

gather(I, N, Array, AVRs) :-
    ( I > N ->
        AVRs = []
    ;
        arg(I, Array, AV),
        I1 is I+1,
        ( var(AV) -> AVRs=AVRs1 ; AVRs = [AV|AVRs1] ),
        gather(I1, N, Array, AVRs1)
    ).

Ответ 4

Эта версия очень короткая, используя member/2 (из пролога Пролога) для поиска. Он имеет очень низкую вспомогательную потребление памяти. Создается только список AVsR. Нет временных Создаются кучи-термины (по текущим реализациям). Он имеет квадратичный накладные расходы на длину AVs.

avs_term_rearranged(AVs, T, AVsR) :-
   term_variables(T, Vs),
   rearrange(Vs, AVs, AVsR).

rearrange([], _, []).
rearrange([V|Vs], AVs, AVsR0) :-
   ( member(AV, AVs),
     AV = (_=Var), V == Var ->
      AVsR0 = [AV|AVsR]
   ;  AVsR0 = AVsR
   ),
   rearrange(Vs, AVs, AVsR).

Другой аспект заключается в том, что цель member(AV, AVs) не детерминированным, даже если только относительно мелкий недетерминизм есть в то время как @jschimpf (первая) версия действительно создает выбор указывает только на (;)/2 реализации if-then-else. Обе версии не оставляют никаких точек выбора.

Вот версия, более точно имитирующая идею @jschimpf. Эта, однако теперь создаются вспомогательные члены, оставшиеся на куче.

rearrange_js([], _, []).
rearrange_js([V|Vs], AVs0, AVsR0) :-
   ( select(AV, AVs0, AVs),
     AV = (_=Var), V == Var ->
      AVsR0 = [AV|AVsR]
   ;  AVsR0 = AVsR,
      AVs0 = AVs
   ),
   rearrange_js(Vs, AVs, AVsR).