# 句法分析-基于CKY的PCFG(概率上下文无法语法)

（新注：根据后来的不断实践，图表中的P和IN是同一个）

[特别像Floyd算法]

# -*- coding: utf-8 -*-
"""
Created on Thu Jan  3 19:58:23 2019

@author: 71405
"""
"""

pi(i,i,N)=N->xi的概率 如果不满足产生式则为0

for l=1:n-1
for i=1:n-l
另 j=i+l
对于所有终结符X计算：
pi(i,j,X)=max(q(X->YZ)*pi(i,s,Y)*pi(s+1,j,Z))  满足X->YZ且 s取值为i到j-1
和bp(i,j,X)=argmax(q(X->YZ)*pi(i,s,Y)*pi(s+1,j,Z))
"""
from collections import defaultdict
import re
if key_a in thedict:
thedict[key_a].update({key_b: val})
else:
thedict.update({key_a:{key_b: val}})

T=['saw','dog','man','telescope','the','with','in']
I=['SS','VP','NP','PP','VT','VI','NN','DT','IN','PX']
p=dict()

sen="the man saw the dog with the telescope"
ss=re.split(r'[\s]',sen)

i=0
while i<len(R1): #去掉'->'符号
R1[i]=R1[i][0:2]+R1[i][4:len(R1[i])-1]
i+=1
i=0
while i<len(R2): #去掉'->'符号
R2[i]=R2[i][0:2]+R2[i][4:len(R2[i])-1]
i+=1

"""
pi设置为二维数组内嵌一元字典
bp同理
"""
N=len(ss)
#初始化
pi=[ [{} for i in range(N)] for i in range(N)]
bp=[ [{} for i in range(N)] for i in range(N)]
for i in range(N):
for x in I:
if x+ss[i] in R2:
pi[i][i][x]=p[x][ss[i]]
else:
pi[i][i][x]=0
l=0
while l<=N-2:
i=0
while i<=N-l-2:
j=i+l+1
for X in I:
s=i
maxi=0
args=-1
while s<=j-1:
for TAB in R1:
if X==TAB[0:2] and len(TAB)==6:
Y=TAB[2:4]
Z=TAB[4:]
maxp=p[X][(Y,Z)]*pi[i][s][Y]*pi[s+1][j][Z]

if maxp>maxi:
maxi=maxp
args=s
s+=1
pi[i][j][X]=maxi
bp[i][j][X]=args
i+=1
l+=1

print('以第一个字符a开始第二个b为结束的段落以X为根的句法树的概率：')
print("a b X   P")
count=0
q=[ [0 for i in range(3)] for i in range(64)]
root=[]
i=0
while i<N:
j=0
while j<N:
if len(pi[i][j])!=0:
for k in pi[i][j]:
if pi[i][j][k]!=0 :
print(str(i)+' '+str(j)+' '+k+' '+str(pi[i][j][k]))
q[count][0]=i
q[count][1]=j
q[count][2]=pi[i][j][k]
count+=1
root.append(k)

j+=1
i+=1
"""
def dp(start,end):
#返回以start为开始end为结束的字符串的最大p
maxi=0
i=0
argc=-1
while i<count:
if q[i][0]==start:
if q[i][1]==end:
maxq=q[i][2]
else:
maxq=q[i][2]*dp(q[i][1]+1,end)
if maxq>maxi:
maxi=maxq
i+=1
return maxi

dp(0,7)
"""

a b X   P
0 0 DT 1.0
0 1 NP 0.21
0 4 SS 0.00504
0 7 SS 5.2919999999999995e-05
1 1 NN 0.7
2 2 VT 1.0
2 4 VP 0.024
2 7 VP 0.000252
3 3 DT 1.0
3 4 NP 0.06
3 7 NP 0.0006299999999999999
4 4 NN 0.2
5 5 IN 0.5
5 7 PP 0.015
6 6 DT 1.0
6 7 NP 0.03
7 7 NN 0.1

【注：1.

i=0

j=0

while i<n

while j<n

2.读取的gram3和gram4分别为图一左表和右表的产生式（为了方便录入NN等字符）

3.由于刚开始对图一P和NN的不可区分性，导致最后运行结果出现了0-4以SS为根的结果，后来思索了一天也没想出来怎么继续做（以为得出来的都是子树然后……） 刚开始用动态规划做（代码在最后注释，留下就当复习算法了），后来想想不太对，没有考虑规则R的问题………………………………直到最后手动建表发现IN没有其他非终结符能产生！然后查了另外一个图（未附）得出结论：P为IN 于是把gramm3和p表中的P更换为IN  跑出了正确的结果 （太尼玛坑了）