2013-05-28 4 views
3

Я пытаюсь написать программу, которая может проверить, может ли программа-ученик выполнить определенную цель или нет. Я могу сделать эту часть. Теперь я хочу проверить, действительно ли программа-ученик содержит ненужный код или нет. Для решения этого случая, я думаю, мне нужно знать, содержит ли студенческая программа факты, которые не вносят вклад в указанную цель. Однако я не могу понять, как найти факты, которые не способствуют достижению цели.Как найти факты, которые не имеют вклада в цель

Чтобы было проще понять, давайте рассмотрим более простой пример. В этом примере указанная цель: является ли джон дедом Томи?

father(john, jim). 
father(jim, tomy). 
father(john, david). 
father(bruce, anne). 
mother(mary, jim). 

grandfather(A,B) :- father(A, X), father(X,B). 

goal:- grandfather(john, tomy). 

На самом деле цель может быть удовлетворена только следующими фактами:

father(john, jim). 
father(jim, tomy). 

И то, что я хочу знать, какие факты, которые на самом деле не способствуют достижению цели. Ответ будет следующим фактом:

father(john, david). 
father(bruce, anne). 
mother(mary, jim). 

Любая помощь действительно оценена. Спасибо

+1

Без дополнительной информации трудно дать какой-либо намек. Какой Пролог? Metainterpreter структура? – CapelliC

+0

Я проделал пролог долгое время, но я не уверен, что здесь будет полезно использовать покрытие кода, поскольку факт может быть оценен в сочетании со многими другими, чтобы попытаться достичь цели, прежде чем она будет позже «отброшена». Возможно, вам нужно что-то, что бы устранить факт, а затем посмотреть, может ли цель все еще быть удовлетворена; Кажется, немного интенсивнее. –

+0

Я уверен, что я помню функцию «trace», которая рассказывает вам, как факты использовались в цели. Возможно, если ваша версия пролога поддерживает эту функцию, вы можете проанализировать этот вывод (простить каламбур), чтобы достичь своей цели. –

ответ

2

Ваш вопрос не может быть напрямую отвечен в Prolog, но вы можете ответить на него вручную, используя failure-slice. Просто добавьте false целей в свою программу и всегда проверяйте, не удастся ли goal. Вот минимальная программа, которую я получил.

 
father(john, jim). 
father(jim, tomy). 
father(john, david) :- false. 
father(bruce, anne) :- false. 
mother(mary, jim) :- false. 

grandfather(A,B) :- father(A, X), father(X,B). 

goal:- grandfather(john, tomy). 

Каждый раз, когда вы вставляете цель false в чистую, монотонной программу, вы знаете наверняка, что множество решений уменьшается (или остается неизменным). Таким образом, поиск такого фрагмента предполагает примерно столько же испытаний, сколько мест для постановки таких целей. Иногда вам может понадобиться добавить цели X = term, чтобы сузить программу еще дальше.

Слизы отказов особенно полезны, если вы хотите понять свойства завершения программы, см. для получения дополнительной информации.

+1

Я действительно не понимаю, как можно использовать срезы отказа, чтобы я мог узнать, что три приведенных выше факта не имеют никакого вклада в достижение цели. Можно ли, например, хранить эти факты в списке? Спасибо –

+1

Подробнее о отказах и ссылках на его реализацию см. Http://stackoverflow.com/questions/10139640/prolog-successor-notation-yields-incomplete-result-and-infinite-loop/10141181#10141181. – false

1

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

Во-первых, вам нужно мета-круговой переводчик:

mi_circ(true). 
mi_circ((A,B)) :- 
    mi_circ(A), 
    mi_circ(B). 
mi_circ(clause(A,B)) :- 
    clause(A,B). 
mi_circ(A \= B) :- 
    A \= B. 
mi_circ(G) :- 
    G \= true, 
    G \= (_,_), 
    G \= (_\=_), 
    G \= clause(_,_), 
    clause(G, Body), 
    mi_circ(Body). 

Это работает для \=/2 и clause/2. Обобщая эту модель для всех встроенных предикатов, мы можем использовать predicate_property/2, чтобы идентифицировать их как таковые для вызова их непосредственно:

provable(true, _) :- !. 
provable((G1,G2), Defs) :- !, 
    provable(G1, Defs), 
    provable(G2, Defs). 
provable(BI, _) :- 
    predicate_property(BI, built_in), 
    !, 
    call(BI). 
provable(Goal, Defs) :- 
    member(Def, Defs), 
    copy_term(Def, Goal-Body), 
    provable(Body, Defs). 

Это дает вам овеществленную мета-интерпретатор, то есть вы можете передать provable/2 цели и набор определений, и он скажет вам, достаточны ли предоставленные определения для доказательства цели. Бьюсь об заклад, вы можете попробовать, насколько мы близки к окончательному решению сейчас!

С помощью следующих дополнительных определений, мы можем использовать это MI, чтобы идентифицировать избыточные факты в некоторых определениях предиката:

redundant(Functor/Arity, Reds) :- 
    functor(Term, Functor, Arity), 
    findall(Term-Body, clause(Term, Body), Defs), 
    setof(Red, Defs^redundant_(Defs, Red), Reds). 

redundant_(Defs, Fact) :- 
    select(Fact-true, Defs, Rest), 
    once(provable(Fact, Rest)). 

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

С учетом определения:

as([]). 
as([a]). % redundant 
as([a,a]). % redundant 
as([A|As]) :- 
    A = a,   % test built-in =/2 
    5 is 2 + 3,  % test built-in is/2 
    1 > 0,   % test built-in >/2 
    as(As). 

мы можем попросить факты, которые выводимы из всех (соответствующие) остальных положений и, следовательно, лишними:

?- redundant(as/1, Reds). 
Reds = [as([a]), as([a, a])] 

Увы, это не работает вне я думаю, что с некоторым изучением вы могли бы найти способ применить эту технику к ней и придумать что-нибудь. Например, вы можете создать мета-интерпретатор, который принимает список фактов, чтобы проверять и выполнять один и тот же тип цикла delete-one-then-proof, чтобы найти их.

Надеюсь, что это поможет и, по крайней мере, интересно.

0

Другой вариант - изменить и использовать инфраструктуру модульного тестирования, которая обеспечивает предикатный охват предложения. Определите единичный тест с целью, для которой вы хотите узнать, какие положения не вносят в нее свой вклад. Бит модификации, если необходимо, будет изменять отчет о покрытии, чтобы также идентифицировать эти предложения. Так же, как пример того, что я имею в виду, в случае, если это не ясно, рассмотрим следующий вывод lgtunit инструмента Logtalk с помощью одного из примеров в распределении Logtalk:

?- {ack(tester)}. 
% 
% tests started at 2013/6/5, 19:54:9 
% running tests from object tests 
% file: /Users/pmoura/logtalk/examples/ack/tests.lgt 
% ack_1: success 
% ack_2: success 
% ack_3: success 
% 3 tests: 0 skipped, 3 passed, 0 failed 
% completed tests from object tests 
% ack: ack/3 - [1,2,3] (3/3) 
% 1 unit declared in the test file containing 3 clauses 
% 1 unit covered containing 3 clauses 
% 3 out of 3 clauses covered, 100,000000% coverage 
% tests ended at 2013/6/5, 19:54:9 
% 
true. 

Линия:

% ack: ack/3 - [1,2,3] (3/3) 

показывает, какие положения использовались тремя модульными тестами для предиката ack/3.