2016-07-08 2 views
3

Я недавно пытался выяснить Пролог и возиться со списками списков в Прологе. Я пытаюсь создать своего рода маску, я полагаю, в p Prolog. У меня есть предикат, который определяет разницу между двумя списками списков (L1 и L2 позволяет сказать) в Prolog и сохраняет их как список списка (Lets say R). У меня есть другой предикат, который просто указывает, равна ли разница нулю (noDifference). Я хотел бы иметь два результирующих списка списков (M1 и M2), основанных на L1 и L2, по сравнению с R. Например, я хотел бы сравнить все значения L1 и L2 с R, если отрицательное значение находится в местоположении из R, тогда значение в том же местоположении L1 сохраняется в M1. И если положительное значение находится в местоположении R, тогда значение в том же месте L2 сохраняется в M2, если это имеет смысл. Прежде всего я проверю с помощью функции noDifference, чтобы увидеть, равна ли разница 0, и если все значения списков списков M1 и M2 будут равны 0.Маскировка в прологе

Это то, что у меня есть до сих пор (я не уверен если бы я начал это право)

masker(L1,L2,R,M1,M2):- noDifference(R1), M1=R, M2=R1; 

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

L1=[[1,5,3,8],[1,5,3,8]] 
L2=[[5,4,7,4],[5,4,7,4]] 
R=[[4,-1,4,-4],[4,-1,4,-4]] 
M1=[[0,5,0,8],[0,5,0,8]]Neg values of L1 at R are stored rest are 0) 
M2=[[5,0,7,0],[5,0,7,0]](Pos values of L2 at R are stored rest are 0) 

Любое понимание, если то, что я делал до сих пор является правильным и как правильно сформулировать подцели, где я должен идти дальше, было бы потрясающе!

редактировать с экс предиката

?- masker([[1,5,3,8],[1,5,3,8]], 
      [[5,4,7,4],[5,4,7,4]], 
      [[4,-1,4,-4],[4,-1,4,-4]], M1, M2). 
M1=[[0,5,0,8],[0,5,0,8]]. 
M2=[[5,0,7,0],[5,0,7,0]]. 
+1

Представьте, что у вас есть рабочий предикат и покажите нам, как вы его используете и какие ответы вы ожидаете. – false

+3

Вы не можете использовать 'is/2' для унификации переменных. 'is/2' для оценки арифметического выражения и объединения результатов с его первым аргументом. Таким образом, 'M1 является R1 'и' M2 является R2', не имеет смысла. Они должны использовать унификацию: «M1 = R1» и «M2 = R2». Что имеется в виду, например, 'L1- [1,5,3,8]'? И 'M1 [0,5,0,8]' недействителен синтаксис Prolog, поэтому неясно, что это значит. – lurker

+0

Хорошо, что имеет смысл спасибо. Это были просто примеры того, что значения должны были быть равны после процедуры, я думаю, я не был уверен, как сделать это очень ясно! – bgibers

ответ

5

Подумайте, что ваш предикат должен описать. Это соотношение между пятью списками списков, которые, согласно приведенному вами примеру, имеют одинаковую длину. Это предполагает базовый случай с пятью пустыми списками. В противном случае главы всех пяти списков сами являются списками, которые находятся в определенном отношении друг к другу, назовем его lists_mask_mlists/5. И, конечно же, то же самое должно быть верно для хвостов, которые могут быть реализованы рекурсивной целью. Таким образом, ваш предикат маскирование/5 может выглядеть примерно так:

masker([],[],[],[],[]). 
masker([X|Xs],[Y|Ys],[M|Ms],[R1|R1s],[R2|R2s]) :- 
    lists_mask_mlists(X,Y,M,R1,R2), 
    masker(Xs,Ys,Ms,R1s,R2s). 

Фактическая маскировка отношение имеет базовый случай с пятью пустыми списками. В противном случае есть еще два случая:

1) Ток маскирующий элемент (глава третьего списка) отрицателен: Глава первого списка является руководителем четвертого списка и главой пятого списка 0

2) текущий элемент маскирования положителен: глава второго списка является главой пятого списка и глава четвертого списка 0

Вы можете выразить, что как так:

lists_mask_mlists([],[],[],[],[]). 
lists_mask_mlists([X|Xs],[_Y|Ys],[M|Ms],[X|R1s],[0|R2s]) :- % 1) 
    M < 0, 
    lists_mask_mlists(Xs,Ys,Ms,R1s,R2s). 
lists_mask_mlists([_X|Xs],[Y|Ys],[M|Ms],[0|R1s],[Y|R2s]) :- % 2) 
    M >= 0, 
    lists_mask_mlists(Xs,Ys,Ms,R1s,R2s). 

С помощью этого предиката вашего примера запрос дает желаемый результат:

?- masker([[1,5,3,8],[1,5,3,8]],[[5,4,7,4],[5,4,7,4]],[[4,-1,4,-4],[4,-1,4,-4]],M1,M2). 
M1 = [[0,5,0,8],[0,5,0,8]], 
M2 = [[5,0,7,0],[5,0,7,0]] ? ; 
no 

Однако обратите внимание, что из-за < и >= это работает только, если третий список переменный бесплатно. Замена первого 4 в третьем аргументе переменным приводит к ошибке создания экземпляра:

?- masker([[1,5,3,8],[1,5,3,8]],[[5,4,7,4],[5,4,7,4]],[[X,-1,4,-4],[4,-1,4,-4]],M1,M2). 
    ERROR at clause 2 of user:masked/5 !! 
    INSTANTIATION ERROR- =:=/2: expected bound value 

Если вы собираетесь использовать предикат с третьим аргументом, который не является переменным свободным, вы могли бы рассмотреть вопрос об использовании clpfd.Включайте линию

:-use_module(library(clpfd)). 

в исходном файле и изменяющие lists_mask_mlists/5 следующим образом:

lists_mask_mlists([],[],[],[],[]). 
lists_mask_mlists([X|Xs],[_Y|Ys],[M|Ms],[X|R1s],[0|R2s]) :- 
    M #< 0,             % <- here 
    lists_mask_mlists(Xs,Ys,Ms,R1s,R2s). 
lists_mask_mlists([_X|Xs],[Y|Ys],[M|Ms],[0|R1s],[Y|R2s]) :- 
    M #>= 0,             % <- here 
    lists_mask_mlists(Xs,Ys,Ms,R1s,R2s). 

Теперь второй вопрос тоже работает:

?- masker([[1,5,3,8],[1,5,3,8]],[[5,4,7,4],[5,4,7,4]],[[X,-1,4,-4],[4,-1,4,-4]],M1,M2). 
M1 = [[1,5,0,8],[0,5,0,8]], 
M2 = [[0,0,7,0],[5,0,7,0]], 
X in inf.. -1 ? ; 
M1 = [[0,5,0,8],[0,5,0,8]], 
M2 = [[5,0,7,0],[5,0,7,0]], 
X in 0..sup ? ; 
no 
+0

Будет ли этот же метод работать, если списки списка были длиннее, чем два? – bgibers

+1

@crosskid: Да, если все соответствующие списки имеют одинаковую длину. То есть списки списков, которые вы передаете в качестве аргументов, должны быть одинаковой длины, а списки в этих списках также должны иметь соответствующую длину. См. Этот запрос, например: '? - masker ([[1,5,3], [1,5,3,8], [1,2]], [[5,4,7], [5,4 , 7,4], [3,4]], [[4, -1, -4], [4, -1,4, -4], [- 1,1]], М1, М2) .' Внутренние списки имеют разную длину друг к другу, но имеют ту же длину, что и другие соответствующие внутренние списки. Таким образом, запрос дает результат: «M1 = [[0,5,3], [0,5,0,8], [1,0]]» и «M2 = [[5,0,0], [ 5,0,7,0], [0,4]] ' – tas

+1

@crosskid: Если вы просто удалите' = 'в случае 2, вы не сможете совместить' 0 's. Вот почему ответ * false *. Вы должны решить, как вы хотите лечить '0'. Вы можете ** a) ** относиться к ним как к положительным числам, что соответствует ответу, который я опубликовал. ** b) ** рассматривать их как отрицательные числа, тогда вы используете 'M # = <0' в случае 1) и' M #> 0' в случае 2). Это дает ответ «M1 = [[0,5,3,8], [0,5,3,8]]» и «M2 = [[5,0,0,0], [5,0,0 , 0]] '. ** c) ** рассматривать их как частный случай, тогда вы используете 'M # <0' в случае 1) и' M #> 0' в случае 2) и добавляете правило для lists_mask_mlists/5 для обработки третьего случая : '0'. – tas

4

@tas представила хорошее решение и объяснение (+1).

Основываясь на этом коде, я хотел бы улучшить космическую эффективность программы. Рассмотрим снова пример запроса с CLP (FD) на основе решения:

 
?- masker([[1,5,3,8],[1,5,3,8]],[[5,4,7,4],[5,4,7,4]],[[4,-1,4,-4],[4,-1,4,-4]],M1,M2). 
M1 = [[0, 5, 0, 8], [0, 5, 0, 8]], 
M2 = [[5, 0, 7, 0], [5, 0, 7, 0]] ; 
false. 

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

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

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

Вместо этого рассмотрите возможность использования if_/3.

Все, что нужно применять if_/3 в этом случае очень легко овеществление в CLP (FD) ограничение   (#<)/2, что легко сделать с zcompare/3:

 
#<(X, Y, T) :- 
     zcompare(C, X, Y), 
     less_true(C, T). 

less_true(<, true). 
less_true(>, false). 
less_true(=, false). 

С этим определением, вся программа становится:

 
:- use_module(library(clpfd)). 

masker([], [], [], [], []). 
masker([X|Xs], [Y|Ys], [M|Ms], [R1|R1s], [R2|R2s]) :- 
     lists_mask_mlists(X, Y, M, R1, R2), 
     masker(Xs, Ys, Ms, R1s, R2s). 

lists_mask_mlists([], [], [], [], []). 
lists_mask_mlists([X|Xs], [Y|Ys], [M|Ms], R1s0, R2s0) :- 
     if_(M #< 0, 
      (R1s0 = [X|R1s], R2s0 = [0|R2s]), 
      (R1s0 = [0|R1s], R2s0 = [Y|R2s])), 
     lists_mask_mlists(Xs, Ys, Ms, R1s, R2s). 

А теперь точка:

 
?- masker([[1,5,3,8],[1,5,3,8]],[[5,4,7,4],[5,4,7,4]],[[4,-1,4,-4],[4,-1,4,-4]],M1,M2). 
M1 = [[0, 5, 0, 8], [0, 5, 0, 8]], 
M2 = [[5, 0, 7, 0], [5, 0, 7, 0]]. 

Этот пример запроса в настоящее время детерминированный!

И программа по-прежнему достаточно общего, чтобы обрабатывать второй пример запроса!

+3

Хорошее улучшение действительно. + s (0) – tas

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