2017-01-18 3 views
0

Я очень неопытен с Prolog. У меня есть набор данных, содержащий элементы и отношения в графе, который имеет округлость (довольно много). Существуют правила для вычисления суммарного отношения пути. Один из них: один берет путь, затем принимает самое слабое отношение, и это тот, который держится между обоими концами.Оптимизация программы Prolog (удаление дубликатов, повторный пересчет)

С элементов E1, E2, E3 и
отношений R1/R1c, R2, R3 (прочность от низкого до высокого) и
структура E1-R3-E2, E1-R1-E2, E2-R2-E3, E3-R1-E2

можно сделать следующий минимальный пример:

% weaker table 
isWeaker(r1, r2). 
isWeaker(r2, r3). 
weaker(X, Y) :- isWeaker(X, Y). 
weaker(X, Y) :- 
    isWeaker(X, Z), 
    weaker(Z, Y). 
% 'weakest' is <= not < 
weakest(X, X, Y) :- =(X,Y). 
weakest(X, X, Y) :- weaker(X, Y). 

% All direct relations 
isADirectRelation(e1, r1, e2). 
isADirectRelation(e1, r3, e2). 
isADirectRelation(e2, r2, e3). 
isADirectRelation(e3, r1, e2). 
isADirectRelation(e1, r3, e4). 
isADirectRelation(e4, r2, e3). 
isADirectRelation(e1, r1, e4). 
isADirectRelation(e3, r1, e4). 

% derived relations calculations 

% Structural Chains 
isADerivedRelation(Source, Relation, Target, Visited) :- 
    \+ member([Source,Relation,Target], Visited), 
    weakest(Relation, RelationOne, RelationTwo), 
    isARelation(Source, RelationOne, Intermediate, [[Source,Relation,Target]|Visited]), 
    isARelation(Intermediate, RelationTwo, Target, [[Source,Relation,Target]|Visited]). 

% major workhorse with anti-circularity 
isARelation(Source, Relation, Target, Visited) :- 
    (isADirectRelation(Source, Relation, Target); 
    isADerivedRelation(Source, Relation, Target, Visited)). 

Результат isARelation(Source, Relation, Target, []). является

e1,r1,e2 
e1,r3,e2 
e2,r2,e3 
e3,r1,e2 
e1,r3,e4 
e4,r2,e3 
e1,r1,e4 
e3,r1,e4 

e1,r1,e3 
e3,r1,e3 
e1,r1,e3 duplicate 
e3,r1,e3 duplicate 

Отсутствующие являются

e4,r1,e4 
e2,r2,e2 

ли вообще возможно решить эту проблему в Прологе? Формально, да, конечно, но и с достойной работой?

+0

Вы уверены, что Prolog является языком \ инструментом для использования? –

+1

Одно небольшое наблюдение: элемент '\ + ([Source, Relation, Target], Посещенные)' call в начале 'isADerivedRelation/4' является избыточным с именем в' isARelation/4', предполагая 'isADerivedRelation/4' в противном случае вызывается только из мест, которые уже проверяют его. Мне также интересно узнать, почему вы пишете '= (X, Y)', а не 'X = Y', или, что еще проще,' самый слабый (X, X, X) .' вместо 'слабый (Weakest, X, Y): - = (Слабый, X), = (X, Y) .' и 'слабый (X, X, Y): - слабее (X, Y).'вместо' слабых (слабых, X, Y): - = (слабый, X), слабее (X, Y) .'. – lurker

+0

Вызов \ + члена в начале isARelation/4 был удален, он блокировал действительный результат e1, r1, e3. Я пишу это так, как я неопытен ... Я не уверен, что Prolog - правильный инструмент, но я пытаюсь это выяснить. Если это сработает, было бы намного легче поддерживать, поскольку мне просто нужно написать правила. – gctwnl

ответ

1

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

Двигаясь дальше, ваш weakest/3 предикат нарушается:

?- weakest(Weakest, r2, r1). 
false. 

Я думаю, что вы имели это право в первой версии вашего вопроса, но тогда вы удалили третий пункт из weakest/3, потому что вы думали, что это вызвало лишние ответы , Излишне говорить, что «эффективность» бесполезна без правильности. (Кроме того, мы обычно ставим «выходные» аргументы последними, а не первыми.)

Часть причин, по которым вы получаете избыточные ответы, - это использование двух (косвенно) рекурсивных вызовов на isARelation/4 в isADerivedRelation/4. То, что вы вычисляете, похоже на переходное закрытие союза «прямых» отношений. Обычный способ выразить транзитивное замыкание в Прологе, как это:

transitive_closure(A, B) :- 
    base_relation(A, B). 
transitive_closure(A, C) :- 
    base_relation(A, B), 
    transitive_closure(B, C). 

То есть, мы первый «взять базовый шаг», то рекурсия. Если наше базовое соотношение имеет пары a-b, b-c, c-d, то это решение найдет решение a-d ровно один раз, как состав базовой пары a-b и производной транзитивной пары b-d. Напротив, если бы мы структурировали второе предложение так же, как и вы, с двумя рекурсивными вызовами до transitive_closure/2, мы получили бы решение a-d дважды: один раз, как указано выше, но также один раз, потому что мы бы вывели транзитивную пару a-c и составили ее с c-d дать a-d.

Вы можете исправить это, изменив первый звонок isARelation/4 в isADerivedRelation/4 в звонок isADirectRelation/3.

Другая проблема заключается в том, что вы используете Visited неправильно: вы отмечаете пару Source-Target как посетили, прежде чем доказали, что такое решение даже существует! Вероятно, вы должны пометить Source-Intermediate как посещенный.

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

Некоторые системы Prolog предлагают функцию, называемую «табуляция», которая в основном кэширует все решения для предиката «набросок» и позволяет избежать повторных вычислений. Это должно избегать избыточных ответов и даже упростить ваше определение: если ваше отношение закрытия указано, вам больше не нужно отслеживать список Visited, потому что циклическая рекомпиментация будет предотвращена таблицей. Я не могу дать вам проверенный код, потому что у меня нет Prolog с таблицей, лежащей вокруг. Даже без табуляции, предлагаемой вашей системой, теоретическая возможность «мнимая» решений сама по себе, используя нечистую базу данных Prolog. Трудно получить это точно, без каких-либо избыточных решений.

В качестве альтернативы нечистому прологу ваша проблема кажется более подходящей для или . Это модели программирования, которые используют синтаксис типа Prolog, но с установленной семантикой, которая, кажется, именно то, что вы хотите: предложение является либо решением, либо нет, нет концепции избыточных решений. Весь набор решений вычисляется за один раз. Удаление цикла также автоматическое, поэтому вам не нужно (фактически, из-за ограниченного языка ввода, не может использовать) список Visited. Если бы я был вами, я попытался бы сделать это в Datalog.

В качестве дополнительного расширения Prolog может быть расширенное решение, основанное на правилах ограничения прав (CHR). Но действительно, попробуйте Datalog.

И наконец, я не понимаю, почему вы считаете, что e2,r2,e2 является недостающим решением. Единственный путь от e2 до e2, который я вижу, проходит через e3 и обратно до e2 через отношение r1, которое является самым слабым, поэтому решение должно быть e2,r1,e2.

+0

Спасибо Изабель. Я был близок к тому, чтобы задать свой собственный ответ (поскольку я исправил свои вещи, и теперь он работает правильно, хотя он не масштабируется (как вы указываете). К счастью, я сначала увидел ваш ответ. Мне было интересно, что у меня есть 4 комбинации: WeakestOne, DirectOne, Two, WeakestTwo, DirectOne, Two, WeakestOne, One, DirectTwo, WeakestTwo, DirectOne, Two, но я думаю, что нет, так как не должно быть разницы в «свертывании» маршрута с одного конца или другого. – gctwnl

+0

Я не могу использовать Source, Target для маркировки, поскольку могут существовать множественные отношения между любыми двумя элементами. Если я попробовал один, я все равно могу получить другое производное отношение с другим. Как показывает пример. И вы правы, e2, r2 , e2 недействителен, я допустил ошибку. – gctwnl

+0

Интересно: могу ли я использовать datalog? Являются ли e1, r1, e3 и e1, r2, e3 избыточными решениями? Мне нужны оба решения. – gctwnl

0

То, что я закончил с, благодаря также комментарии Lurker и ответ Изабель это:

% weaker table 
isWeaker(r1, r2). 
isWeaker(r2, r3). 
weaker(X, Y) :- isWeaker(X, Y). 
weaker(X, Y) :- 
    isWeaker(X, Z), 
    weaker(Z, Y). 
% 'weakest' is <= not < 
weakest(X, X, Y) :- =(X,Y). 
weakest(X, X, Y) :- weaker(X, Y). 

% All direct relations 
isADirectRelation(e1, r1, e2). 
isADirectRelation(e1, r3, e2). 
isADirectRelation(e2, r2, e3). 
isADirectRelation(e3, r1, e2). 
isADirectRelation(e1, r3, e4). 
isADirectRelation(e4, r2, e3). 
isADirectRelation(e1, r1, e4). 
isADirectRelation(e3, r1, e4). 

% derived relations calculations 

isARelation(Source, Relation, Target, _) :- 
    isADirectRelation(Source, Relation, Target). 

% Structural Chains 
isARelation(Source, Relation, Target, Visited) :- 
    \+ member([Source,Relation,Target], Visited), 
    weakest(Relation, RelationOne, RelationTwo), 
    isADirectRelation(Source, RelationOne, Intermediate), 
    isARelation(Intermediate, RelationTwo, Target, [[Source,RelationOne,Intermediate]|Visited]). 
isARelation(Source, Relation, Target, Visited) :- 
    \+ member([Source,Relation,Target], Visited), 
    weakest(Relation, RelationOne, RelationTwo), 
    isADirectRelation(Source, RelationTwo, Intermediate), 
    isARelation(Intermediate, RelationOne, Target, [[Source,RelationTwo,Intermediate]|Visited]). 

write_relation(Result) :- 
    write(Result), nl. 

writeAllRelations :- 
    setof((Relation, Source, Target), Relation^isARelation(Source, Relation, Target, []), ListOfAllRelations), 
% maplist(write_relation, ListOfAllRelations). % For SWIProlog 
write(ListOfAllRelations). % for JIProlog 

Это работает и производит ли он прав результат:

r1,e1,e2 
r1,e1,e3 
r1,e1,e4 
r1,e2,e2 
r1,e2,e3 
r1,e2,e4 
r1,e3,e2 
r1,e3,e3 
r1,e3,e4 
r1,e4,e2 
r1,e4,e3 
r1,e4,e4 
r2,e1,e3 
r2,e2,e3 
r2,e4,e3 
r3,e1,e2 
r3,e1,e4 

Однако в реального мира, с 60 или около того сущностей и 800 или около того прямых отношений, я не нашел Пролог, который может справиться с этим. Я посмотрю на Datalog.