Как компактно выразить дизъюнкт неравенств без лишних ответов/решений

Рассмотрим, что я пробовал:

dif_to_orto(A, B, C) :-
   (  dif(A, B)
   ;  dif(A, C)
   ).

Хотя это определение прекрасно с декларативной точки зрения, оно содержит много избыточности. Думать о:

?- dif_to_orto(A, B, C), A = 1, B = 2, C = 2.
   A = 1, B = 2, C = 2
;  A = 1, B = 2, C = 2.   % unexpected redundant solution

И даже не в этом случае:

?- dif_to_orto(A, B, C), A = 1, B = 2, C = 3.
   A = 1, B = 2, C = 3
;  A = 1, B = 2, C = 3.   % unexpected redundant solution

По крайней мере, здесь случай без излишеств...

?- dif_to_orto(A, B, C), A = 1, B = 2, C = 1.
   A = 1, B = 2, C = 1
;  false.                 % unexpected inefficient leftover choicepoint

... но с оставшейся точкой выбора, которая тратит ресурсы.

Редко бывают случаи, когда это определение эффективно:

?- dif_to_orto(A, B, C), A = 1, B = 1, C = 2.
   A = 1, B = 1, C = 2.

Кроме того, тот факт, что самый общий запрос дает два ответа, кажется мне очень неэффективным:

?- dif_to_orto(A, B, C).
   dif:dif(A,B)
;  dif:dif(A,C).

... что создает также следующую избыточность:

?- dif_to_orto(1, B, B).
   dif:dif(1,B)
;  dif:dif(1,B).    % unexpected redundant answer

Одного dif/2 было бы достаточно!

Есть ли способ избежать всей этой избыточности и неэффективности?


person false    schedule 05.02.2021    source источник
comment
не являются ли повторяющиеся решения из-за того, что B равно C? как насчет dif(B,C) во втором случае?   -  person coredump    schedule 05.02.2021
comment
@coredump: добавлено два случая для уточнения.   -  person false    schedule 05.02.2021


Ответы (4)


Как насчет этого:

dif_to_orto(A, B, C) :-
   dif(A-A, B-C).

Тестовые случаи:

?- dif_to_orto(A, B, C), A = 1, B = 2, C = 2.
A = 1,
B = C, C = 2.

?- dif_to_orto(A, B, C), A = 1, B = 2, C = 3.
A = 1,
B = 2,
C = 3.

?- dif_to_orto(A, B, C), A = 1, B = 2, C = 1.
A = C, C = 1,
B = 2.

?- dif_to_orto(A, B, C), A = 1, B = 1, C = 2.
A = B, B = 1,
C = 2.

?- dif_to_orto(A, B, C).
dif(f(B, A), f(A, C)).

?- dif_to_orto(1, B, B).
dif(B, 1).
person DuDa    schedule 05.02.2021
comment
@false Я озадачен. Я сделал что-то не так? Должен ли я отказаться от этого ответа? - person DuDa; 06.02.2021
comment
Нет, выглядит как идеальный ответ - person false; 06.02.2021
comment
dif_to_orto(1, B, B). еще один хороший случай - person false; 06.02.2021
comment
В SICStus два последних вызова дают разные результаты: prolog:dif(A-A,B-C) и prolog:dif(1-1,B-B) соответственно. Таким образом, цель dif/2 не упрощается. Я думаю, что поведение в конечном итоге такое же, но я подумал, что стоит это отметить... - person jnmonette; 08.02.2021
comment
@jnmonette: SICStus показывает первоначальную цель, которая, по крайней мере, в первом случае гораздо более интуитивно понятна, чем то, что вы получаете в SWI с его структурой из ниоткуда f/2. Во втором случае SWI на самом деле приятнее. - person false; 09.02.2021

Это решение сначала ожидает, что 2 из 3 переменных будут сопоставимы, а затем, если оно не может решить, должно ли ограничение быть успешным, добавляет новое ограничение:

dif_to_orto(A, B, C) :-
    when((?=(A, B) ; ?=(A, C) ; ?=(B, C)),
         (   ?=(A, B) ->
              ( A\==B ->  true ; dif(A, C) )
         ;
             (
                ?=(A, C) ->
                 ( A\==C -> true ; dif(A, B) )
             ;
                 ( B\==C -> true ; dif(A, B) )
             )
         )).

Примеры запусков:

?- dif_to_orto(A, B, C), A = 1, B = 2, C = 2.
A = 1,
B = C, C = 2.

?- dif_to_orto(A, B, C), A = 1, B = 2, C = 3.
A = 1,
B = 2,
C = 3.

?- dif_to_orto(A, B, C), A = 1, B = 2, C = 1.
A = C, C = 1,
B = 2.

?- dif_to_orto(A, B, C).
when((?=(A, C);?=(B, C);?=(A, B)),  (?=(A, B)->(A\==B->true;dif(A, C));?=(A, C)->(A\==C->true;dif(A, B));B\==C->true;dif(A, B))).

?- dif_to_orto(1, 2, Z).
true.

?- dif_to_orto(1, B, B).
dif(B, 1).

Отмена чеков:

dif_to_orto(A, B, C) :-
    when((?=(A, B) ; ?=(A, C) ; ?=(B, C)),
         (
           A==B -> dif(A, C)
           ;
           ((A==C ; B==C) -> dif(A, B) ; true)
         )).
person gusbro    schedule 05.02.2021
comment
Но гораздо лучше, dif_to_orto(1, B, B)... - person false; 05.02.2021
comment
хе-хе, вы хотите добавить третье сравнение... проверим - person gusbro; 05.02.2021
comment
@false: добавлена ​​другая ветка. - person gusbro; 05.02.2021

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

dif_to_orto(A, B, C) :-
   when(?=(A,B),(A==B->dif(A,C);true)),
   when(?=(A,C),(A==C->dif(A,B);true)).

Для каждого дизъюнкта подождите, пока не станет известно, является ли он истинным или ложным. После того, как он известен, проверьте его истинность и, если он неверен, опубликуйте другой дизъюнкт.

person jnmonette    schedule 05.02.2021
comment
dif_to_orto(1, 2, Z). дает when(?=(1, Z), (1==Z->dif(1, 2);true)). Как я могу быть уверен, что это не равносильно false? - person false; 05.02.2021
comment
Кстати, если у вас есть другое решение, поместите его в другой ответ, чтобы мы могли проголосовать, принять и наградить их один за другим. - person false; 05.02.2021

Расширение определения dif/2:

dif_to_orto(A, B, C):-
   when((?=(A,B), ?=(A, C)), (A \== B -> true ; A \== C)).

Примеры запусков:

?- dif_to_orto(A, B, C), A = 1, B = 2, C = 2.
A = 1,
B = C, C = 2.

?- dif_to_orto(A, B, C), A = 1, B = 2, C = 3.
A = 1,
B = 2,
C = 3.

?- dif_to_orto(A, B, C), A = 1, B = 2, C = 1.
A = C, C = 1,
B = 2.

?- dif_to_orto(A, B, C).
when((?=(A, B), ?=(A, C)),  (A\==B->true;A\==C)).
person gusbro    schedule 05.02.2021
comment
dif_to_orto(1, 2, Z). имеет некоторые ограничения, связанные с Z. Почему? Как я могу быть уверен, что это не имеет значения. - person false; 05.02.2021
comment
Этот ответ задерживает оценку ограничения до тех пор, пока все три переменные не могут быть синтаксически сопоставлены, поэтому в вашем примере я вижу только то, что ручная проверка приостановленной цели определяет, что она будет успешной. Может быть, откладывать оценку до тех пор, пока три из них не будут сопоставимы, тогда не лучшая идея... - person gusbro; 05.02.2021
comment
Попробуйте другой. - person false; 05.02.2021
comment
Кстати, синтаксис здесь специфичен для SWI - person false; 05.02.2021
comment
@false: вы имеете в виду использование when/2 и dif/2? Я не вижу их в GProlog. У меня нет лицензии на Sicstus, поэтому я не особо знаком с их аналогами. - person gusbro; 05.02.2021
comment
Просто отсутствует пара круглых скобок вокруг if-then-else. - person false; 05.02.2021
comment
Или (в SWI), скажем, listing(dif_to_orto) - person false; 05.02.2021
comment
Я вижу это по последнему пробному запуску, отпечатки if-then-else заключены в круглые скобки. Фиксированный код - person gusbro; 05.02.2021