将自然语言转化为逻辑公式
Convert natural language into logical formula
我尝试了好几天来编写一个 NLTK 语法来将简单的法语句子转换为逻辑公式。我的问题可能与英语句子相似。我的目标是该语法接受多个命令(家庭自动化)并将它们转换为逻辑公式。一些订单示例:
开灯:
exists x.(turn_on(x) & light(x))
开绿灯:
exists x.(turn_on(x) & light(x) & green(x))
打开厨房的灯
exists x.(turn_on(x) & light(x) & exists y.(kitchen(y) & in(x, y)))
在这些示例中,单词 turn_on 并不是真正的逻辑谓词。它将在我的程序的下一步中使用(当它将此公式转换为另一种表示时)。
但是,关于占有关系的规则,我写起来有很多困难。我希望该规则接受 "infinite" 递归,例如:
- 打开厨房的灯(灯属于我数据库中的厨房)
- 打开房子厨房的灯(厨房在我的数据库中属于房子)
- 打开[...](等)房子的厨房灯
我成功转换了第一句话但没有转换其他句子。这是我的语法(我将法语翻译成英语以便更好地理解):
% start SV
SV[SEM=<?v(?sn)>] -> V[SEM=?v] SN[SEM=?sn]
SN[SEM=<?ap(?sn1, ?sn2)>] -> SN[SEM=?sn1] AP[SEM=?ap] SN[SEM=?sn2]
SN[SEM=<?ad(?n)>] -> AD[SEM=?ad] N[SEM=?n]
SN[SEM=?n] -> N[SEM=?n]
N[SEM=<?adj(?n)>] -> ADJ[SEM=?adj] N[SEM=?n]
V[SEM=<\P.P(\x.turn_on(x))>] -> 'turn' 'on'
N[SEM=<\x.light(x)>] -> 'light'
N[SEM=<\x.kitchen(x)>] -> 'kitchen'
N[SEM=<\x.house(x)>] -> 'house'
ADJ[SEM=<\P x.(P(x) & big(x))>] -> 'big'
ADJ[SEM=<\P x.(P(x) & green(x))>] -> 'green'
AD[SEM=<\P Q.exists x.(P(x) & Q(x))>] -> 'the'
AP[SEM=<\P Q R.Q(\x.P(\y.(in(y,x) & R(y))))>] -> 'of'
根据这个语法和顺序 "turn on the light of the kitchen",我得到:
exists x.(kitchen(x) & exists z1.(light(z1) & in(z1,x) & turn_on(z1)))
但是,对于订单 "turn on the light of the kitchen of the house":
exists x.(house(x) & exists z5.(kitchen(z5) & exists z2.(light(z2) & in(z2,z5) & in(z2,x) & turn_on(z2))))
为了更具可读性,相同的公式没有 "exists":
(house(x4) & kitchen(x6) & light(x7) & in(x7,x6) & in(x7,x4) & turn_on(x7))
"in" 谓词有问题。事实上,我希望灯在厨房里,厨房在房子里。然而,在这种情况下,灯在厨房和房子里(是的,这是真的,但我不希望那样 =/)。这是我想要的:
(house(x4) & kitchen(x6) & light(x7) & in(x7,x6) & in(x6,x4) & turn_on(x7))
the difference -----^
我尝试了几种方法,但其中 none 有效...你能帮帮我吗?我不知道我的语法是否可行。我对逻辑和 lambda 演算的了解有限,我才刚刚开始对这些话题感兴趣。
编辑:
这是我用于测试的 python 代码:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import nltk
def exec(parser, query):
try:
trees = list(parser.parse(query.split()))
except ValueError:
print('Invalid query')
return
if len(trees) == 0:
print('Invalid query')
return
print('query: %s' % query)
print('results:')
for t in trees:
sem = t.label()['SEM']
print('\t%s' % sem)
print('')
if __name__ == '__main__':
parser = nltk.load_parser('./en_grammar.fcfg')
exec(parser, 'turn on the light')
exec(parser, 'turn on the light of the kitchen')
exec(parser, 'turn on the light of the kitchen of the house')
非常感谢,对不起我的英语。
很难说存在量词是祈使句的逻辑形式。但是,你的问题出在另一个问题上。
看来你的语法有歧义。特别是当你用 in(x, y)
函数解释 x of y
时,可以想象到与第二个短语类似的歧义:
the light of the kitchen in the house .
the ball of the kid in the yard .
- 在院子里的球。
- 院子里的孩子
你的语法基于你的代码对所需的句子产生了这两种解释:
query: turn on the light of the kitchen of the house
results:
exists x.(house(x) & exists z5.(kitchen(z5) & exists z2.(light(z2) & in(z2,z5) & in(z2,x) & turn_on(z2))))
exists x.(house(x) & exists z3.(kitchen(z3) & in(z3,x) & exists z6.(light(z6) & in(z6,z3) & turn_on(z6))))
第二种解释:house(x) & exists z3.(kitchen(z3) & in(z3,x) ...
正是您想要的。
更新:
让我们尽量避免 x of y of z
.
链中的歧义
强制使用 x of (y of z)
而不是 (x of y) of z
的一个非常快速的解决方案是跟踪所有名词短语中 of
的用法,然后强制它没有 OF
在 of
的左侧:
SN[SEM=<?ap(?sn1, ?sn2)>, +OF] -> SN[SEM=?sn1, -OF] AP[SEM=?ap] SN[SEM=?sn2]
SN[SEM=<?ad(?n)>, -OF] -> AD[SEM=?ad] N[SEM=?n]
SN[SEM=?n, -OF] -> N[SEM=?n]
我尝试了好几天来编写一个 NLTK 语法来将简单的法语句子转换为逻辑公式。我的问题可能与英语句子相似。我的目标是该语法接受多个命令(家庭自动化)并将它们转换为逻辑公式。一些订单示例:
开灯:
exists x.(turn_on(x) & light(x))
开绿灯:
exists x.(turn_on(x) & light(x) & green(x))
打开厨房的灯
exists x.(turn_on(x) & light(x) & exists y.(kitchen(y) & in(x, y)))
在这些示例中,单词 turn_on 并不是真正的逻辑谓词。它将在我的程序的下一步中使用(当它将此公式转换为另一种表示时)。
但是,关于占有关系的规则,我写起来有很多困难。我希望该规则接受 "infinite" 递归,例如:
- 打开厨房的灯(灯属于我数据库中的厨房)
- 打开房子厨房的灯(厨房在我的数据库中属于房子)
- 打开[...](等)房子的厨房灯
我成功转换了第一句话但没有转换其他句子。这是我的语法(我将法语翻译成英语以便更好地理解):
% start SV
SV[SEM=<?v(?sn)>] -> V[SEM=?v] SN[SEM=?sn]
SN[SEM=<?ap(?sn1, ?sn2)>] -> SN[SEM=?sn1] AP[SEM=?ap] SN[SEM=?sn2]
SN[SEM=<?ad(?n)>] -> AD[SEM=?ad] N[SEM=?n]
SN[SEM=?n] -> N[SEM=?n]
N[SEM=<?adj(?n)>] -> ADJ[SEM=?adj] N[SEM=?n]
V[SEM=<\P.P(\x.turn_on(x))>] -> 'turn' 'on'
N[SEM=<\x.light(x)>] -> 'light'
N[SEM=<\x.kitchen(x)>] -> 'kitchen'
N[SEM=<\x.house(x)>] -> 'house'
ADJ[SEM=<\P x.(P(x) & big(x))>] -> 'big'
ADJ[SEM=<\P x.(P(x) & green(x))>] -> 'green'
AD[SEM=<\P Q.exists x.(P(x) & Q(x))>] -> 'the'
AP[SEM=<\P Q R.Q(\x.P(\y.(in(y,x) & R(y))))>] -> 'of'
根据这个语法和顺序 "turn on the light of the kitchen",我得到:
exists x.(kitchen(x) & exists z1.(light(z1) & in(z1,x) & turn_on(z1)))
但是,对于订单 "turn on the light of the kitchen of the house":
exists x.(house(x) & exists z5.(kitchen(z5) & exists z2.(light(z2) & in(z2,z5) & in(z2,x) & turn_on(z2))))
为了更具可读性,相同的公式没有 "exists":
(house(x4) & kitchen(x6) & light(x7) & in(x7,x6) & in(x7,x4) & turn_on(x7))
"in" 谓词有问题。事实上,我希望灯在厨房里,厨房在房子里。然而,在这种情况下,灯在厨房和房子里(是的,这是真的,但我不希望那样 =/)。这是我想要的:
(house(x4) & kitchen(x6) & light(x7) & in(x7,x6) & in(x6,x4) & turn_on(x7))
the difference -----^
我尝试了几种方法,但其中 none 有效...你能帮帮我吗?我不知道我的语法是否可行。我对逻辑和 lambda 演算的了解有限,我才刚刚开始对这些话题感兴趣。
编辑: 这是我用于测试的 python 代码:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import nltk
def exec(parser, query):
try:
trees = list(parser.parse(query.split()))
except ValueError:
print('Invalid query')
return
if len(trees) == 0:
print('Invalid query')
return
print('query: %s' % query)
print('results:')
for t in trees:
sem = t.label()['SEM']
print('\t%s' % sem)
print('')
if __name__ == '__main__':
parser = nltk.load_parser('./en_grammar.fcfg')
exec(parser, 'turn on the light')
exec(parser, 'turn on the light of the kitchen')
exec(parser, 'turn on the light of the kitchen of the house')
非常感谢,对不起我的英语。
很难说存在量词是祈使句的逻辑形式。但是,你的问题出在另一个问题上。
看来你的语法有歧义。特别是当你用 in(x, y)
函数解释 x of y
时,可以想象到与第二个短语类似的歧义:
the light of the kitchen in the house .
the ball of the kid in the yard .
- 在院子里的球。
- 院子里的孩子
你的语法基于你的代码对所需的句子产生了这两种解释:
query: turn on the light of the kitchen of the house
results:
exists x.(house(x) & exists z5.(kitchen(z5) & exists z2.(light(z2) & in(z2,z5) & in(z2,x) & turn_on(z2))))
exists x.(house(x) & exists z3.(kitchen(z3) & in(z3,x) & exists z6.(light(z6) & in(z6,z3) & turn_on(z6))))
第二种解释:house(x) & exists z3.(kitchen(z3) & in(z3,x) ...
正是您想要的。
更新:
让我们尽量避免 x of y of z
.
强制使用 x of (y of z)
而不是 (x of y) of z
的一个非常快速的解决方案是跟踪所有名词短语中 of
的用法,然后强制它没有 OF
在 of
的左侧:
SN[SEM=<?ap(?sn1, ?sn2)>, +OF] -> SN[SEM=?sn1, -OF] AP[SEM=?ap] SN[SEM=?sn2]
SN[SEM=<?ad(?n)>, -OF] -> AD[SEM=?ad] N[SEM=?n]
SN[SEM=?n, -OF] -> N[SEM=?n]