从知识库中获取随机谓词.序言

nub*_*nub 2 random predicate prolog

例如,我有:

upred(mary, have, knife).
upred(john, have,  sword).
upred(sam, have, bowl).
upred(sword, is,  long).
Run Code Online (Sandbox Code Playgroud)

我怎样才能获得随机谓词?

% call this and get random predicate as Pred
get_random_pred(Pred) :-
Run Code Online (Sandbox Code Playgroud)

Dan*_*ons 5

有趣的是,这也是我最近一直在担心的事情.我有一个部分解决方案,它依赖于动态存储并识别您希望能够随机获得的事实.我不喜欢它,因为它确实依赖于动态存储,也因为它依赖于元数据的制作,而元数据的制作可能是未经同步的.但是,它可能足以满足您的目的.它也不能很好地捕捉你的API,因为你必须提供一些线索,你感兴趣的是什么"实物".在实践中,它可能会成功,但是你可能不会发现自己任何事实都会发生的情况,因为它可能会在下一次模式匹配时失败.

我的基本技巧是用来=..反汇编谓词,并用来asserta为每个事实分配一个索引值.如果你希望这个表现更好,你必须使用一些索引指令来告诉Prolog你希望它一直索引到我的第三个字段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), !.
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这里的引擎基本上是为了给定一个目标并构建一个小元数据库.知道Prolog比我更了解的人可能会改善它.要使用它,你就像这样驾驶它:

?- prepare_randomization_metadata(upred(X, Y, Z)).
true.
Run Code Online (Sandbox Code Playgroud)

现在你有一个包含事实的数据库,如下所示:

random_fact(upred, upred(mary, have, knife), 0).
random_fact(upred, upred(john, have, sword), 1).
...
Run Code Online (Sandbox Code Playgroud)

这是你可以用Prolog推理的东西.因此,如果您想要第二个谓词,您可以像这样查询它:

?- random_fact(upred, X, 1)
X = upred(mary, have, knife) ;
false.
Run Code Online (Sandbox Code Playgroud)

现在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), !.
Run Code Online (Sandbox Code Playgroud)

我还不够好Prolog告诉你为什么这有时候我认为它有多种解决方案,但确实如此,所以我在最后插入了红色切口.但是,如果你想要多种解决方案,那么写一个版本也很容易.

endless_random_facts(Head, Fact) :- repeat, get_random_pred(Head, Fact).
Run Code Online (Sandbox Code Playgroud)

例如:

?- 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) ;
Run Code Online (Sandbox Code Playgroud)

无论如何,我希望这有所帮助,尽管存在不足之处.我只在SWI-Prolog中测试过.