gpt4 book ai didi

algorithm - 从具有给定终端数的文法中生成一个句子

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:12:54 24 4
gpt4 key购买 nike

假设您有一个玩具语法,例如:(更新后输出看起来更自然)

S -> ${NP} ${VP} | ${S} and ${S} | ${S}, after which ${S}

NP -> the ${N} | the ${A} ${N} | the ${A} ${A} ${N}

VP -> ${V} ${NP}

N -> dog | fish | bird | wizard

V -> kicks | meets | marries

A -> red | striped | spotted

例如,“狗踢红色巫师”、“鸟遇到 Blob 鱼或巫师娶条纹狗”

根据必须包含总共 n Vs + As + Ns 的约束,你如何从这个文法中产生一个句子。给定一个整数,句子必须包含那么多终端。 (当然请注意,在此语法中,可能的最小 n 是 3)。

最佳答案

以下 Python 代码将生成具有给定终端数的随机句子。它的工作原理是计算生成给定长度句子的方法数,生成一个大的随机数,然后计算指定的句子。计数是通过内存递归完成的。如果 n 为 0,则空白右侧会产生 1 个句子,否则会产生 0 个句子。要计算非空右侧生成的句子数,请对右侧第一个符号使用的终端数 i 求和。对于每个 i,将右侧其余部分的可能性数乘以第一个符号的可能性数。如果第一个符号是终结符号,则如果 i 为 1 则有 1 种可能性,否则为 0。如果第一个符号是非终结符号,则对每个备选方案的可能性求和。为避免无限循环,我们必须小心修剪数量为 0 时的递归调用。如果语法对一个句子有无限多的推导,这仍然可能无限循环。例如,在语法中

S -> S S
S ->

空句有无穷多个推导:S => , S => S S => , S => S S => S S S => 等。查找特定句子的代码是对计算它们的代码的直接修改。此代码相当高效,在不到一秒的时间内生成了 100 个句子,每个句子有 100 个终端。

import collections
import random

class Grammar:
def __init__(self):
self.prods = collections.defaultdict(list)
self.numsent = {}
self.weight = {}

def prod(self, lhs, *rhs):
self.prods[lhs].append(rhs)
self.numsent.clear()

def countsent(self, rhs, n):
if n < 0:
return 0
elif not rhs:
return 1 if n == 0 else 0
args = (rhs, n)
if args not in self.numsent:
sym = rhs[0]
rest = rhs[1:]
total = 0
if sym in self.prods:
for i in xrange(1, n + 1):
numrest = self.countsent(rest, n - i)
if numrest > 0:
for rhs1 in self.prods[sym]:
total += self.countsent(rhs1, i) * numrest
else:
total += self.countsent(rest, n - self.weight.get(sym, 1))
self.numsent[args] = total
return self.numsent[args]

def getsent(self, rhs, n, j):
assert 0 <= j < self.countsent(rhs, n)
if not rhs:
return ()
sym = rhs[0]
rest = rhs[1:]
if sym in self.prods:
for i in xrange(1, n + 1):
numrest = self.countsent(rest, n - i)
if numrest > 0:
for rhs1 in self.prods[sym]:
dj = self.countsent(rhs1, i) * numrest
if dj > j:
j1, j2 = divmod(j, numrest)
return self.getsent(rhs1, i, j1) + self.getsent(rest, n - i, j2)
j -= dj
assert False
else:
return (sym,) + self.getsent(rest, n - self.weight.get(sym, 1), j)

def randsent(self, sym, n):
return self.getsent((sym,), n, random.randrange(self.countsent((sym,), n)))

if __name__ == '__main__':
g = Grammar()
g.prod('S', 'NP', 'VP')
g.prod('S', 'S', 'and', 'S')
g.prod('S', 'S', 'after', 'which', 'S')
g.prod('NP', 'the', 'N')
g.prod('NP', 'the', 'A', 'N')
g.prod('NP', 'the', 'A', 'A', 'N')
g.prod('VP', 'V', 'NP')
g.prod('N', 'dog')
g.prod('N', 'fish')
g.prod('N', 'bird')
g.prod('N', 'wizard')
g.prod('V', 'kicks')
g.prod('V', 'meets')
g.prod('V', 'marries')
g.prod('A', 'red')
g.prod('A', 'striped')
g.prod('A', 'spotted')
g.weight.update({'and': 0, 'after': 0, 'which': 0, 'the': 0})
for i in xrange(100):
print ' '.join(g.randsent('S', 3))

关于algorithm - 从具有给定终端数的文法中生成一个句子,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/966576/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com