Получить случайный предикат из базы знаний. пролог - PullRequest
2 голосов
/ 20 сентября 2011

Например, у меня есть:

upred(mary, have, knife).
upred(john, have,  sword).
upred(sam, have, bowl).
upred(sword, is,  long).

Как получить случайный предикат?

% call this and get random predicate as Pred
get_random_pred(Pred) :-

Ответы [ 2 ]

5 голосов
/ 21 сентября 2011

Забавно, это то, о чем я беспокоюсь и в последнее время.У меня есть частичное решение, которое зависит от динамического хранилища и определения фактов, которые вы хотите получить случайным образом.Я не влюблен в это, потому что это зависит от динамического хранилища, а также потому, что это зависит от изготовления метаданных, которые могут быть не синхронизированы.Тем не менее, это может быть достаточно для ваших целей.Он также не полностью отражает ваш API, потому что вы должны предложить некоторую подсказку, какой «вид» факта вас интересует. На практике это, вероятно, сработает нормально, потому что вы вряд ли окажетесь вситуация, в которой любой факт может сработать, потому что он, вероятно, потерпит неудачу при следующем сопоставлении с образцом.

Моя основная хитрость заключается в том, чтобы использовать =.. для разборки предикатов и использовать asserta дляприсвойте каждому факту значение индекса.Если вы хотите, чтобы это работало лучше, вам придется использовать некоторую директиву индексации, чтобы сказать Прологу, что вы хотите, чтобы она индексировалась полностью до третьего поля моего random_fact, но я не зашел так далеко.Для небольших баз данных (не WordNet) это, вероятно, будет в порядке, но для более крупных вам, вероятно, понадобится производительность.

% random_fact(Head, Instantiation, Index)
:- dynamic(random_fact/3).

% fact_count(Head, Count)
:- dynamic(fact_count/2).

% one big side-effect to make it possible to query for a random predicate
prepare_randomization_metadata(Goal) :-
  findall(Goal, Goal, Occurrances),
  prepare_randomization_metadata(Occurrances, 0),
  Goal =.. [Head|_],
  length(Occurrances, N),
  asserta(fact_count(Head, N)).

prepare_randomization_metadata([], _).
prepare_randomization_metadata([Goal|Goals], N) :-
  Goal =.. [Head|_],
  asserta(random_fact(Head, Goal, N)),
  N1 is N+1,
  prepare_randomization_metadata(Goals, N1), !.

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

?- prepare_randomization_metadata(upred(X, Y, Z)).
true.

Теперь у вас есть база данных с такими фактами:

random_fact(upred, upred(mary, have, knife), 0).
random_fact(upred, upred(john, have, sword), 1).
...

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

?- random_fact(upred, X, 1)
X = upred(mary, have, knife) ;
false.

Теперь get_random_pred довольно просто, но нам нужен дополнительный аргумент для определения того «вида» факта, который нам нужен:

get_random_pred(Head, Pred) :-
  fact_count(Head, N),
  % pick a random number between 0 and the # of facts we have for this pred
  random(0, N, I),
  random_fact(Head, Pred, I), !.

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

endless_random_facts(Head, Fact) :- repeat, get_random_pred(Head, Fact).

Например:

?- get_random_pred(upred, X).
X = upred(sword, is, long) ;
X = upred(john, have, sword) ;
X = upred(mary, have, knife) ;
X = upred(john, have, sword) ;
X = upred(john, have, sword) ;

В любом случае, надеюсь, это поможет,несмотря на недостатки.Я тестировал только в SWI-Prolog.

0 голосов
/ 08 мая 2019

SWI-Prolog имеет nth_clause / 3 , поэтому я думаю, что простое решение будет:

?- I is random(4)+1, nth_clause(upred(_,_,_), I, R), clause(H, B, R).
I = 1,
R = <clause>(0000018B7AECE610),
H = upred(mary, have, knife),
B = true.

?- I is random(4)+1, nth_clause(upred(_,_,_), I, R), clause(H, B, R).
I = 2,
R = <clause>(0000018B7AECC690),
H = upred(john, have, sword),
B = true.

Вы также можете использовать свойство предиката number_of_clauses / 1.

...