Получить случайный предикат из базы знаний. Пролог

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

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) :-

person nub    schedule 20.09.2011    source источник
comment
Случайно как в...?! Можете ли вы дать образец результата для Pred? Из какого множества значений следует брать аргументы предиката?   -  person ThomasH    schedule 20.09.2011


Ответы (2)


Забавно, в последнее время я тоже беспокоюсь об этом. У меня есть частичное решение, которое зависит от динамического хранилища и определения фактов, которые вы хотите получить случайным образом. Мне это не нравится, потому что это зависит от динамического хранилища, а также потому, что это зависит от изготовления метаданных, которые могут стать несинхронизированными. Тем не менее, этого может быть достаточно для ваших целей. Он также не полностью отражает ваш 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.

person Daniel Lyons    schedule 21.09.2011

В 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.

person Mostowski Collapse    schedule 08.05.2019