nltk 3.2__zip → 3.3__zip

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (406) hide show
  1. {nltk-3.2 → nltk-3.3}/INSTALL.txt +6 -6
  2. {nltk-3.2 → nltk-3.3}/LICENSE.txt +13 -13
  3. {nltk-3.2 → nltk-3.3}/MANIFEST.in +6 -6
  4. {nltk-3.2/nltk.egg-info → nltk-3.3}/PKG-INFO +13 -5
  5. nltk-3.2/README.txt → nltk-3.3/README.md +49 -48
  6. nltk-3.3/nltk/VERSION +1 -0
  7. {nltk-3.2 → nltk-3.3}/nltk/__init__.py +185 -185
  8. {nltk-3.2 → nltk-3.3}/nltk/app/__init__.py +52 -53
  9. {nltk-3.2 → nltk-3.3}/nltk/app/chartparser_app.py +2276 -2276
  10. {nltk-3.2 → nltk-3.3}/nltk/app/chunkparser_app.py +1262 -1264
  11. {nltk-3.2 → nltk-3.3}/nltk/app/collocations_app.py +347 -350
  12. {nltk-3.2 → nltk-3.3}/nltk/app/concordance_app.py +568 -570
  13. {nltk-3.2 → nltk-3.3}/nltk/app/nemo_app.py +156 -155
  14. {nltk-3.2 → nltk-3.3}/nltk/app/rdparser_app.py +892 -894
  15. {nltk-3.2 → nltk-3.3}/nltk/app/srparser_app.py +809 -809
  16. {nltk-3.2 → nltk-3.3}/nltk/app/wordfreq_app.py +32 -32
  17. {nltk-3.2 → nltk-3.3}/nltk/app/wordnet_app.py +968 -968
  18. {nltk-3.2 → nltk-3.3}/nltk/book.py +91 -90
  19. {nltk-3.2 → nltk-3.3}/nltk/ccg/__init__.py +22 -22
  20. {nltk-3.2 → nltk-3.3}/nltk/ccg/api.py +359 -335
  21. {nltk-3.2 → nltk-3.3}/nltk/ccg/chart.py +394 -361
  22. {nltk-3.2 → nltk-3.3}/nltk/ccg/combinator.py +343 -312
  23. {nltk-3.2 → nltk-3.3}/nltk/ccg/lexicon.py +328 -290
  24. nltk-3.3/nltk/ccg/logic.py +46 -0
  25. {nltk-3.2 → nltk-3.3}/nltk/chat/__init__.py +49 -49
  26. {nltk-3.2 → nltk-3.3}/nltk/chat/eliza.py +244 -244
  27. {nltk-3.2 → nltk-3.3}/nltk/chat/iesha.py +140 -140
  28. {nltk-3.2 → nltk-3.3}/nltk/chat/rude.py +92 -92
  29. {nltk-3.2 → nltk-3.3}/nltk/chat/suntsu.py +117 -117
  30. {nltk-3.2 → nltk-3.3}/nltk/chat/util.py +122 -120
  31. {nltk-3.2 → nltk-3.3}/nltk/chat/zen.py +282 -282
  32. {nltk-3.2 → nltk-3.3}/nltk/chunk/__init__.py +190 -190
  33. {nltk-3.2 → nltk-3.3}/nltk/chunk/api.py +51 -51
  34. {nltk-3.2 → nltk-3.3}/nltk/chunk/named_entity.py +331 -331
  35. {nltk-3.2 → nltk-3.3}/nltk/chunk/regexp.py +1390 -1384
  36. {nltk-3.2 → nltk-3.3}/nltk/chunk/util.py +600 -600
  37. {nltk-3.2 → nltk-3.3}/nltk/classify/__init__.py +98 -98
  38. {nltk-3.2 → nltk-3.3}/nltk/classify/api.py +193 -193
  39. {nltk-3.2 → nltk-3.3}/nltk/classify/decisiontree.py +295 -295
  40. {nltk-3.2 → nltk-3.3}/nltk/classify/maxent.py +1510 -1492
  41. {nltk-3.2 → nltk-3.3}/nltk/classify/megam.py +179 -178
  42. {nltk-3.2 → nltk-3.3}/nltk/classify/naivebayes.py +245 -242
  43. {nltk-3.2 → nltk-3.3}/nltk/classify/positivenaivebayes.py +170 -170
  44. {nltk-3.2 → nltk-3.3}/nltk/classify/rte_classify.py +160 -191
  45. {nltk-3.2 → nltk-3.3}/nltk/classify/scikitlearn.py +153 -151
  46. {nltk-3.2 → nltk-3.3}/nltk/classify/senna.py +183 -181
  47. {nltk-3.2 → nltk-3.3}/nltk/classify/svm.py +15 -15
  48. {nltk-3.2 → nltk-3.3}/nltk/classify/tadm.py +113 -112
  49. {nltk-3.2 → nltk-3.3}/nltk/classify/textcat.py +193 -193
  50. {nltk-3.2 → nltk-3.3}/nltk/classify/util.py +324 -312
  51. {nltk-3.2 → nltk-3.3}/nltk/classify/weka.py +346 -345
  52. {nltk-3.2 → nltk-3.3}/nltk/cluster/__init__.py +86 -86
  53. {nltk-3.2 → nltk-3.3}/nltk/cluster/api.py +74 -70
  54. {nltk-3.2 → nltk-3.3}/nltk/cluster/em.py +247 -247
  55. {nltk-3.2 → nltk-3.3}/nltk/cluster/gaac.py +168 -168
  56. {nltk-3.2 → nltk-3.3}/nltk/cluster/kmeans.py +221 -221
  57. {nltk-3.2 → nltk-3.3}/nltk/cluster/util.py +304 -289
  58. nltk-3.3/nltk/collections.py +640 -0
  59. {nltk-3.2 → nltk-3.3}/nltk/collocations.py +388 -388
  60. nltk-3.3/nltk/compat.py +365 -0
  61. {nltk-3.2 → nltk-3.3}/nltk/corpus/__init__.py +341 -320
  62. {nltk-3.2 → nltk-3.3}/nltk/corpus/europarl_raw.py +44 -44
  63. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/__init__.py +147 -145
  64. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/aligned.py +115 -114
  65. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/api.py +448 -446
  66. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/bnc.py +252 -252
  67. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/bracket_parse.py +227 -227
  68. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/categorized_sents.py +179 -178
  69. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/chasen.py +140 -139
  70. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/childes.py +522 -494
  71. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/chunked.py +212 -212
  72. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/cmudict.py +97 -95
  73. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/comparative_sents.py +280 -278
  74. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/conll.py +528 -521
  75. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/crubadan.py +116 -116
  76. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/dependency.py +101 -101
  77. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/framenet.py +3059 -2093
  78. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ieer.py +112 -111
  79. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/indian.py +85 -86
  80. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ipipan.py +332 -331
  81. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/knbc.py +187 -187
  82. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/lin.py +156 -156
  83. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/mte.py +311 -310
  84. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nkjp.py +429 -428
  85. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nombank.py +421 -421
  86. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nps_chat.py +73 -73
  87. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/opinion_lexicon.py +115 -115
  88. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/panlex_lite.py +165 -165
  89. nltk-3.3/nltk/corpus/reader/pl196x.py +292 -0
  90. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/plaintext.py +232 -233
  91. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ppattach.py +96 -95
  92. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/propbank.py +479 -481
  93. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/pros_cons.py +128 -126
  94. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/reviews.py +330 -328
  95. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/rte.py +144 -146
  96. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/semcor.py +256 -256
  97. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/senseval.py +203 -201
  98. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/sentiwordnet.py +137 -137
  99. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/sinica_treebank.py +75 -75
  100. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/string_category.py +60 -59
  101. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/switchboard.py +119 -119
  102. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/tagged.py +295 -294
  103. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/timit.py +452 -450
  104. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/toolbox.py +68 -68
  105. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/twitter.py +155 -157
  106. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/udhr.py +80 -80
  107. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/util.py +804 -800
  108. nltk-3.3/nltk/corpus/reader/verbnet.py +595 -0
  109. nltk-3.3/nltk/corpus/reader/wordlist.py +134 -0
  110. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/wordnet.py +2108 -2036
  111. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/xmldocs.py +392 -387
  112. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ycoe.py +243 -242
  113. {nltk-3.2 → nltk-3.3}/nltk/corpus/util.py +144 -127
  114. {nltk-3.2 → nltk-3.3}/nltk/data.py +1487 -1451
  115. {nltk-3.2 → nltk-3.3}/nltk/decorators.py +219 -215
  116. {nltk-3.2 → nltk-3.3}/nltk/downloader.py +2278 -2274
  117. {nltk-3.2 → nltk-3.3}/nltk/draw/__init__.py +27 -27
  118. {nltk-3.2 → nltk-3.3}/nltk/draw/cfg.py +774 -777
  119. {nltk-3.2 → nltk-3.3}/nltk/draw/dispersion.py +58 -58
  120. {nltk-3.2 → nltk-3.3}/nltk/draw/table.py +1098 -1098
  121. {nltk-3.2 → nltk-3.3}/nltk/draw/tree.py +963 -966
  122. {nltk-3.2 → nltk-3.3}/nltk/draw/util.py +2356 -2356
  123. {nltk-3.2 → nltk-3.3}/nltk/featstruct.py +2617 -2500
  124. {nltk-3.2 → nltk-3.3}/nltk/grammar.py +1559 -1516
  125. {nltk-3.2 → nltk-3.3}/nltk/help.py +56 -56
  126. {nltk-3.2 → nltk-3.3}/nltk/inference/__init__.py +20 -20
  127. {nltk-3.2 → nltk-3.3}/nltk/inference/api.py +597 -589
  128. {nltk-3.2 → nltk-3.3}/nltk/inference/discourse.py +612 -608
  129. {nltk-3.2 → nltk-3.3}/nltk/inference/mace.py +311 -311
  130. {nltk-3.2 → nltk-3.3}/nltk/inference/nonmonotonic.py +509 -509
  131. {nltk-3.2 → nltk-3.3}/nltk/inference/prover9.py +431 -431
  132. {nltk-3.2 → nltk-3.3}/nltk/inference/resolution.py +687 -687
  133. {nltk-3.2 → nltk-3.3}/nltk/inference/tableau.py +607 -607
  134. {nltk-3.2 → nltk-3.3}/nltk/internals.py +982 -982
  135. {nltk-3.2 → nltk-3.3}/nltk/jsontags.py +63 -63
  136. {nltk-3.2 → nltk-3.3}/nltk/lazyimport.py +142 -142
  137. {nltk-3.2 → nltk-3.3}/nltk/metrics/__init__.py +30 -29
  138. {nltk-3.2 → nltk-3.3}/nltk/metrics/agreement.py +421 -401
  139. nltk-3.3/nltk/metrics/aline.py +607 -0
  140. {nltk-3.2 → nltk-3.3}/nltk/metrics/association.py +414 -410
  141. {nltk-3.2 → nltk-3.3}/nltk/metrics/confusionmatrix.py +206 -206
  142. {nltk-3.2 → nltk-3.3}/nltk/metrics/distance.py +207 -202
  143. {nltk-3.2 → nltk-3.3}/nltk/metrics/paice.py +381 -381
  144. {nltk-3.2 → nltk-3.3}/nltk/metrics/scores.py +228 -228
  145. {nltk-3.2 → nltk-3.3}/nltk/metrics/segmentation.py +231 -232
  146. {nltk-3.2 → nltk-3.3}/nltk/metrics/spearman.py +69 -69
  147. {nltk-3.2 → nltk-3.3}/nltk/misc/__init__.py +11 -11
  148. {nltk-3.2 → nltk-3.3}/nltk/misc/babelfish.py +10 -10
  149. {nltk-3.2 → nltk-3.3}/nltk/misc/chomsky.py +135 -133
  150. {nltk-3.2 → nltk-3.3}/nltk/misc/minimalset.py +83 -83
  151. {nltk-3.2 → nltk-3.3}/nltk/misc/sort.py +157 -157
  152. {nltk-3.2 → nltk-3.3}/nltk/misc/wordfinder.py +129 -129
  153. {nltk-3.2 → nltk-3.3}/nltk/parse/__init__.py +81 -80
  154. {nltk-3.2 → nltk-3.3}/nltk/parse/api.py +66 -66
  155. {nltk-3.2 → nltk-3.3}/nltk/parse/bllip.py +282 -282
  156. {nltk-3.2 → nltk-3.3}/nltk/parse/chart.py +1682 -1681
  157. nltk-3.3/nltk/parse/corenlp.py +780 -0
  158. {nltk-3.2 → nltk-3.3}/nltk/parse/dependencygraph.py +760 -758
  159. {nltk-3.2 → nltk-3.3}/nltk/parse/earleychart.py +452 -451
  160. {nltk-3.2 → nltk-3.3}/nltk/parse/evaluate.py +129 -129
  161. {nltk-3.2 → nltk-3.3}/nltk/parse/featurechart.py +580 -578
  162. {nltk-3.2 → nltk-3.3}/nltk/parse/generate.py +87 -76
  163. {nltk-3.2 → nltk-3.3}/nltk/parse/malt.py +356 -356
  164. {nltk-3.2 → nltk-3.3}/nltk/parse/nonprojectivedependencyparser.py +783 -783
  165. {nltk-3.2 → nltk-3.3}/nltk/parse/pchart.py +522 -522
  166. {nltk-3.2 → nltk-3.3}/nltk/parse/projectivedependencyparser.py +579 -578
  167. {nltk-3.2 → nltk-3.3}/nltk/parse/recursivedescent.py +655 -656
  168. {nltk-3.2 → nltk-3.3}/nltk/parse/shiftreduce.py +458 -459
  169. {nltk-3.2 → nltk-3.3}/nltk/parse/stanford.py +431 -406
  170. {nltk-3.2 → nltk-3.3}/nltk/parse/transitionparser.py +774 -772
  171. {nltk-3.2 → nltk-3.3}/nltk/parse/util.py +231 -231
  172. {nltk-3.2 → nltk-3.3}/nltk/parse/viterbi.py +401 -401
  173. {nltk-3.2 → nltk-3.3}/nltk/probability.py +2410 -2355
  174. {nltk-3.2 → nltk-3.3}/nltk/sem/__init__.py +61 -61
  175. {nltk-3.2 → nltk-3.3}/nltk/sem/boxer.py +1261 -1261
  176. {nltk-3.2 → nltk-3.3}/nltk/sem/chat80.py +782 -782
  177. {nltk-3.2 → nltk-3.3}/nltk/sem/cooper_storage.py +118 -118
  178. {nltk-3.2 → nltk-3.3}/nltk/sem/drt.py +1258 -1257
  179. {nltk-3.2 → nltk-3.3}/nltk/sem/drt_glue_demo.py +485 -489
  180. {nltk-3.2 → nltk-3.3}/nltk/sem/evaluate.py +790 -784
  181. {nltk-3.2 → nltk-3.3}/nltk/sem/glue.py +696 -694
  182. {nltk-3.2 → nltk-3.3}/nltk/sem/hole.py +386 -384
  183. {nltk-3.2 → nltk-3.3}/nltk/sem/lfg.py +210 -208
  184. {nltk-3.2 → nltk-3.3}/nltk/sem/linearlogic.py +451 -449
  185. {nltk-3.2 → nltk-3.3}/nltk/sem/logic.py +1910 -1910
  186. {nltk-3.2 → nltk-3.3}/nltk/sem/relextract.py +476 -483
  187. {nltk-3.2 → nltk-3.3}/nltk/sem/skolemize.py +101 -101
  188. {nltk-3.2 → nltk-3.3}/nltk/sem/util.py +249 -249
  189. {nltk-3.2 → nltk-3.3}/nltk/sentiment/__init__.py +14 -14
  190. {nltk-3.2 → nltk-3.3}/nltk/sentiment/sentiment_analyzer.py +229 -229
  191. {nltk-3.2 → nltk-3.3}/nltk/sentiment/util.py +762 -752
  192. {nltk-3.2 → nltk-3.3}/nltk/sentiment/vader.py +443 -445
  193. {nltk-3.2 → nltk-3.3}/nltk/stem/__init__.py +31 -33
  194. {nltk-3.2 → nltk-3.3}/nltk/stem/api.py +28 -25
  195. nltk-3.3/nltk/stem/arlstem.py +369 -0
  196. {nltk-3.2 → nltk-3.3}/nltk/stem/isri.py +345 -345
  197. {nltk-3.2 → nltk-3.3}/nltk/stem/lancaster.py +337 -310
  198. nltk-3.3/nltk/stem/porter.py +710 -0
  199. {nltk-3.2 → nltk-3.3}/nltk/stem/regexp.py +61 -61
  200. {nltk-3.2 → nltk-3.3}/nltk/stem/rslp.py +142 -142
  201. {nltk-3.2 → nltk-3.3}/nltk/stem/snowball.py +4236 -3712
  202. {nltk-3.2 → nltk-3.3}/nltk/stem/util.py +22 -12
  203. {nltk-3.2 → nltk-3.3}/nltk/stem/wordnet.py +51 -51
  204. {nltk-3.2 → nltk-3.3}/nltk/tag/__init__.py +152 -127
  205. {nltk-3.2 → nltk-3.3}/nltk/tag/api.py +86 -81
  206. {nltk-3.2 → nltk-3.3}/nltk/tag/brill.py +424 -426
  207. {nltk-3.2 → nltk-3.3}/nltk/tag/brill_trainer.py +608 -608
  208. {nltk-3.2 → nltk-3.3}/nltk/tag/crf.py +204 -200
  209. {nltk-3.2 → nltk-3.3}/nltk/tag/hmm.py +1277 -1277
  210. {nltk-3.2 → nltk-3.3}/nltk/tag/hunpos.py +132 -132
  211. {nltk-3.2 → nltk-3.3}/nltk/tag/mapping.py +101 -101
  212. {nltk-3.2 → nltk-3.3}/nltk/tag/perceptron.py +329 -314
  213. {nltk-3.2 → nltk-3.3}/nltk/tag/senna.py +147 -145
  214. {nltk-3.2 → nltk-3.3}/nltk/tag/sequential.py +740 -736
  215. {nltk-3.2 → nltk-3.3}/nltk/tag/stanford.py +219 -196
  216. {nltk-3.2 → nltk-3.3}/nltk/tag/tnt.py +595 -604
  217. {nltk-3.2 → nltk-3.3}/nltk/tag/util.py +72 -72
  218. {nltk-3.2 → nltk-3.3}/nltk/tbl/__init__.py +28 -28
  219. {nltk-3.2 → nltk-3.3}/nltk/tbl/api.py +1 -1
  220. {nltk-3.2 → nltk-3.3}/nltk/tbl/demo.py +366 -366
  221. {nltk-3.2 → nltk-3.3}/nltk/tbl/erroranalysis.py +39 -39
  222. {nltk-3.2 → nltk-3.3}/nltk/tbl/feature.py +259 -261
  223. {nltk-3.2 → nltk-3.3}/nltk/tbl/rule.py +321 -321
  224. {nltk-3.2 → nltk-3.3}/nltk/tbl/template.py +303 -308
  225. {nltk-3.2 → nltk-3.3}/nltk/test/__init__.py +18 -18
  226. {nltk-3.2 → nltk-3.3}/nltk/test/all.py +24 -23
  227. {nltk-3.2 → nltk-3.3}/nltk/test/bleu.doctest +14 -14
  228. {nltk-3.2 → nltk-3.3}/nltk/test/bnc.doctest +60 -60
  229. {nltk-3.2 → nltk-3.3}/nltk/test/ccg.doctest +376 -395
  230. nltk-3.3/nltk/test/ccg_semantics.doctest +553 -0
  231. {nltk-3.2 → nltk-3.3}/nltk/test/chat80.doctest +234 -234
  232. {nltk-3.2 → nltk-3.3}/nltk/test/childes.doctest +184 -184
  233. {nltk-3.2 → nltk-3.3}/nltk/test/childes_fixt.py +14 -13
  234. {nltk-3.2 → nltk-3.3}/nltk/test/chunk.doctest +373 -373
  235. {nltk-3.2 → nltk-3.3}/nltk/test/classify.doctest +185 -185
  236. {nltk-3.2 → nltk-3.3}/nltk/test/classify_fixt.py +11 -10
  237. nltk-3.3/nltk/test/collections.doctest +20 -0
  238. {nltk-3.2 → nltk-3.3}/nltk/test/collocations.doctest +276 -276
  239. {nltk-3.2 → nltk-3.3}/nltk/test/compat.doctest +134 -138
  240. {nltk-3.2 → nltk-3.3}/nltk/test/compat_fixt.py +9 -8
  241. nltk-3.3/nltk/test/concordance.doctest +55 -0
  242. {nltk-3.2 → nltk-3.3}/nltk/test/corpus.doctest +2200 -2212
  243. {nltk-3.2 → nltk-3.3}/nltk/test/corpus_fixt.py +3 -3
  244. {nltk-3.2 → nltk-3.3}/nltk/test/crubadan.doctest +65 -65
  245. {nltk-3.2 → nltk-3.3}/nltk/test/data.doctest +379 -379
  246. {nltk-3.2 → nltk-3.3}/nltk/test/dependency.doctest +241 -241
  247. {nltk-3.2 → nltk-3.3}/nltk/test/discourse.doctest +546 -546
  248. {nltk-3.2 → nltk-3.3}/nltk/test/discourse_fixt.py +14 -13
  249. {nltk-3.2 → nltk-3.3}/nltk/test/doctest_nose_plugin.py +159 -156
  250. {nltk-3.2 → nltk-3.3}/nltk/test/drt.doctest +517 -517
  251. {nltk-3.2 → nltk-3.3}/nltk/test/featgram.doctest +607 -607
  252. {nltk-3.2 → nltk-3.3}/nltk/test/featstruct.doctest +1229 -1230
  253. {nltk-3.2 → nltk-3.3}/nltk/test/framenet.doctest +288 -239
  254. {nltk-3.2 → nltk-3.3}/nltk/test/generate.doctest +67 -67
  255. {nltk-3.2 → nltk-3.3}/nltk/test/gensim.doctest +140 -141
  256. {nltk-3.2 → nltk-3.3}/nltk/test/gensim_fixt.py +10 -9
  257. {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics.doctest +384 -386
  258. {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics_malt.doctest +68 -68
  259. {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics_malt_fixt.py +12 -11
  260. {nltk-3.2 → nltk-3.3}/nltk/test/grammar.doctest +48 -48
  261. {nltk-3.2 → nltk-3.3}/nltk/test/grammartestsuites.doctest +109 -109
  262. {nltk-3.2 → nltk-3.3}/nltk/test/index.doctest +100 -100
  263. {nltk-3.2 → nltk-3.3}/nltk/test/inference.doctest +534 -534
  264. {nltk-3.2 → nltk-3.3}/nltk/test/inference_fixt.py +12 -11
  265. {nltk-3.2 → nltk-3.3}/nltk/test/internals.doctest +140 -140
  266. {nltk-3.2 → nltk-3.3}/nltk/test/japanese.doctest +48 -48
  267. {nltk-3.2 → nltk-3.3}/nltk/test/logic.doctest +1098 -1098
  268. {nltk-3.2 → nltk-3.3}/nltk/test/metrics.doctest +270 -270
  269. {nltk-3.2 → nltk-3.3}/nltk/test/misc.doctest +118 -118
  270. {nltk-3.2 → nltk-3.3}/nltk/test/nonmonotonic.doctest +286 -286
  271. {nltk-3.2 → nltk-3.3}/nltk/test/nonmonotonic_fixt.py +12 -11
  272. {nltk-3.2 → nltk-3.3}/nltk/test/paice.doctest +35 -35
  273. {nltk-3.2 → nltk-3.3}/nltk/test/parse.doctest +884 -884
  274. {nltk-3.2 → nltk-3.3}/nltk/test/portuguese_en.doctest +565 -565
  275. {nltk-3.2 → nltk-3.3}/nltk/test/portuguese_en_fixt.py +16 -16
  276. {nltk-3.2 → nltk-3.3}/nltk/test/probability.doctest +304 -304
  277. {nltk-3.2 → nltk-3.3}/nltk/test/probability_fixt.py +13 -12
  278. {nltk-3.2 → nltk-3.3}/nltk/test/propbank.doctest +176 -176
  279. {nltk-3.2 → nltk-3.3}/nltk/test/relextract.doctest +263 -263
  280. {nltk-3.2 → nltk-3.3}/nltk/test/resolution.doctest +221 -221
  281. {nltk-3.2 → nltk-3.3}/nltk/test/runtests.py +86 -64
  282. {nltk-3.2 → nltk-3.3}/nltk/test/segmentation_fixt.py +10 -10
  283. {nltk-3.2 → nltk-3.3}/nltk/test/semantics.doctest +665 -665
  284. {nltk-3.2 → nltk-3.3}/nltk/test/semantics_fixt.py +7 -7
  285. {nltk-3.2 → nltk-3.3}/nltk/test/sentiment.doctest +233 -233
  286. {nltk-3.2 → nltk-3.3}/nltk/test/sentiwordnet.doctest +41 -41
  287. {nltk-3.2 → nltk-3.3}/nltk/test/simple.doctest +85 -85
  288. {nltk-3.2 → nltk-3.3}/nltk/test/stem.doctest +78 -78
  289. {nltk-3.2 → nltk-3.3}/nltk/test/tag.doctest +33 -33
  290. {nltk-3.2 → nltk-3.3}/nltk/test/tokenize.doctest +273 -166
  291. {nltk-3.2 → nltk-3.3}/nltk/test/toolbox.doctest +307 -307
  292. {nltk-3.2 → nltk-3.3}/nltk/test/translate.doctest +242 -242
  293. {nltk-3.2 → nltk-3.3}/nltk/test/translate_fixt.py +3 -3
  294. {nltk-3.2 → nltk-3.3}/nltk/test/tree.doctest +1101 -1101
  295. {nltk-3.2 → nltk-3.3}/nltk/test/treeprettyprinter.doctest +127 -127
  296. {nltk-3.2 → nltk-3.3}/nltk/test/treetransforms.doctest +156 -156
  297. nltk-3.3/nltk/test/unit/test_2x_compat.py +63 -0
  298. nltk-3.3/nltk/test/unit/test_aline.py +52 -0
  299. nltk-3.3/nltk/test/unit/test_chunk.py +56 -0
  300. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_classify.py +55 -53
  301. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_collocations.py +88 -79
  302. nltk-3.3/nltk/test/unit/test_concordance.py +98 -0
  303. nltk-3.3/nltk/test/unit/test_corenlp.py +1000 -0
  304. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_corpora.py +200 -183
  305. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_corpus_views.py +45 -45
  306. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_hmm.py +88 -88
  307. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_json2csv_corpus.py +188 -187
  308. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_naivebayes.py +26 -26
  309. nltk-3.3/nltk/test/unit/test_rte_classify.py +86 -0
  310. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_seekable_unicode_stream_reader.py +124 -124
  311. nltk-3.3/nltk/test/unit/test_senna.py +74 -0
  312. nltk-3.3/nltk/test/unit/test_stem.py +121 -0
  313. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_tag.py +20 -20
  314. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_tgrep.py +628 -626
  315. nltk-3.3/nltk/test/unit/test_tokenize.py +168 -0
  316. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_twitter_auth.py +185 -185
  317. nltk-3.3/nltk/test/unit/test_wordnet.py +134 -0
  318. nltk-3.3/nltk/test/unit/translate/test_bleu.py +244 -0
  319. nltk-3.3/nltk/test/unit/translate/test_gdfa.py +57 -0
  320. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm1.py +75 -75
  321. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm2.py +87 -87
  322. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm3.py +105 -105
  323. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm4.py +126 -126
  324. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm5.py +166 -166
  325. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm_model.py +270 -270
  326. nltk-3.3/nltk/test/unit/translate/test_nist.py +37 -0
  327. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_stack_decoder.py +300 -300
  328. {nltk-3.2 → nltk-3.3}/nltk/test/unit/utils.py +41 -41
  329. {nltk-3.2 → nltk-3.3}/nltk/test/util.doctest +48 -48
  330. {nltk-3.2 → nltk-3.3}/nltk/test/wordnet.doctest +595 -581
  331. {nltk-3.2 → nltk-3.3}/nltk/test/wordnet_fixt.py +7 -6
  332. {nltk-3.2 → nltk-3.3}/nltk/test/wordnet_lch.doctest +53 -53
  333. {nltk-3.2 → nltk-3.3}/nltk/test/wsd.doctest +68 -68
  334. {nltk-3.2 → nltk-3.3}/nltk/text.py +663 -610
  335. {nltk-3.2 → nltk-3.3}/nltk/tgrep.py +938 -937
  336. {nltk-3.2 → nltk-3.3}/nltk/tokenize/__init__.py +130 -107
  337. {nltk-3.2 → nltk-3.3}/nltk/tokenize/api.py +77 -78
  338. {nltk-3.2 → nltk-3.3}/nltk/tokenize/casual.py +343 -342
  339. {nltk-3.2 → nltk-3.3}/nltk/tokenize/mwe.py +120 -120
  340. nltk-3.3/nltk/tokenize/nist.py +173 -0
  341. {nltk-3.2 → nltk-3.3}/nltk/tokenize/punkt.py +1620 -1601
  342. {nltk-3.2 → nltk-3.3}/nltk/tokenize/regexp.py +208 -202
  343. nltk-3.3/nltk/tokenize/repp.py +151 -0
  344. {nltk-3.2 → nltk-3.3}/nltk/tokenize/sexpr.py +140 -142
  345. {nltk-3.2 → nltk-3.3}/nltk/tokenize/simple.py +138 -136
  346. {nltk-3.2 → nltk-3.3}/nltk/tokenize/stanford.py +117 -113
  347. nltk-3.3/nltk/tokenize/stanford_segmenter.py +246 -0
  348. {nltk-3.2 → nltk-3.3}/nltk/tokenize/texttiling.py +458 -460
  349. nltk-3.3/nltk/tokenize/toktok.py +155 -0
  350. nltk-3.3/nltk/tokenize/treebank.py +363 -0
  351. nltk-3.3/nltk/tokenize/util.py +261 -0
  352. {nltk-3.2 → nltk-3.3}/nltk/toolbox.py +499 -497
  353. {nltk-3.2 → nltk-3.3}/nltk/translate/__init__.py +24 -24
  354. {nltk-3.2 → nltk-3.3}/nltk/translate/api.py +331 -321
  355. {nltk-3.2 → nltk-3.3}/nltk/translate/bleu_score.py +615 -556
  356. nltk-3.3/nltk/translate/chrf_score.py +137 -0
  357. {nltk-3.2 → nltk-3.3}/nltk/translate/gale_church.py +248 -235
  358. {nltk-3.2 → nltk-3.3}/nltk/translate/gdfa.py +135 -131
  359. nltk-3.3/nltk/translate/gleu_score.py +193 -0
  360. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm1.py +250 -241
  361. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm2.py +308 -308
  362. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm3.py +337 -337
  363. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm4.py +467 -467
  364. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm5.py +639 -639
  365. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm_model.py +536 -533
  366. {nltk-3.2 → nltk-3.3}/nltk/translate/metrics.py +40 -40
  367. nltk-3.3/nltk/translate/nist_score.py +178 -0
  368. {nltk-3.2 → nltk-3.3}/nltk/translate/phrase_based.py +175 -175
  369. {nltk-3.2 → nltk-3.3}/nltk/translate/ribes_score.py +325 -325
  370. {nltk-3.2 → nltk-3.3}/nltk/translate/stack_decoder.py +499 -495
  371. {nltk-3.2 → nltk-3.3}/nltk/tree.py +1605 -1603
  372. {nltk-3.2 → nltk-3.3}/nltk/treeprettyprinter.py +564 -564
  373. {nltk-3.2 → nltk-3.3}/nltk/treetransforms.py +309 -309
  374. {nltk-3.2 → nltk-3.3}/nltk/twitter/__init__.py +28 -28
  375. {nltk-3.2 → nltk-3.3}/nltk/twitter/api.py +141 -136
  376. {nltk-3.2 → nltk-3.3}/nltk/twitter/common.py +264 -258
  377. {nltk-3.2 → nltk-3.3}/nltk/twitter/twitter_demo.py +288 -288
  378. {nltk-3.2 → nltk-3.3}/nltk/twitter/twitterclient.py +530 -530
  379. {nltk-3.2 → nltk-3.3}/nltk/twitter/util.py +147 -146
  380. nltk-3.3/nltk/util.py +751 -0
  381. {nltk-3.2 → nltk-3.3}/nltk/wsd.py +53 -53
  382. {nltk-3.2 → nltk-3.3/nltk.egg-info}/PKG-INFO +13 -5
  383. {nltk-3.2 → nltk-3.3}/nltk.egg-info/SOURCES.txt +26 -3
  384. nltk-3.3/nltk.egg-info/requires.txt +31 -0
  385. {nltk-3.2 → nltk-3.3}/setup.cfg +0 -1
  386. {nltk-3.2 → nltk-3.3}/setup.py +102 -75
  387. nltk-3.2/nltk/VERSION +0 -1
  388. nltk-3.2/nltk/compat.py +0 -680
  389. nltk-3.2/nltk/corpus/reader/pl196x.py +0 -278
  390. nltk-3.2/nltk/corpus/reader/verbnet.py +0 -408
  391. nltk-3.2/nltk/corpus/reader/wordlist.py +0 -37
  392. nltk-3.2/nltk/sentiment/vader_lexicon.txt +0 -7517
  393. nltk-3.2/nltk/six.py +0 -868
  394. nltk-3.2/nltk/stem/porter.py +0 -692
  395. nltk-3.2/nltk/test/unit/test_2x_compat.py +0 -26
  396. nltk-3.2/nltk/test/unit/test_stem.py +0 -36
  397. nltk-3.2/nltk/test/unit/test_tokenize.py +0 -23
  398. nltk-3.2/nltk/test/unit/translate/test_bleu.py +0 -84
  399. nltk-3.2/nltk/tokenize/treebank.py +0 -124
  400. nltk-3.2/nltk/tokenize/util.py +0 -90
  401. nltk-3.2/nltk/util.py +0 -1364
  402. {nltk-3.2 → nltk-3.3}/nltk/test/unit/__init__.py +0 -0
  403. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/__init__.py +0 -0
  404. {nltk-3.2 → nltk-3.3}/nltk.egg-info/dependency_links.txt +0 -0
  405. {nltk-3.2 → nltk-3.3}/nltk.egg-info/not-zip-safe +0 -0
  406. {nltk-3.2 → nltk-3.3}/nltk.egg-info/top_level.txt +0 -0
@@ -1,1516 +1,1559 @@
1
- # -*- coding: utf-8 -*-
2
- # Natural Language Toolkit: Context Free Grammars
3
- #
4
- # Copyright (C) 2001-2015 NLTK Project
5
- # Author: Steven Bird <stevenbird1@gmail.com>
6
- # Edward Loper <edloper@gmail.com>
7
- # Jason Narad <jason.narad@gmail.com>
8
- # Peter Ljunglöf <peter.ljunglof@heatherleaf.se>
9
- # URL: <http://nltk.org/>
10
- # For license information, see LICENSE.TXT
11
- #
12
-
13
- """
14
- Basic data classes for representing context free grammars. A
15
- "grammar" specifies which trees can represent the structure of a
16
- given text. Each of these trees is called a "parse tree" for the
17
- text (or simply a "parse"). In a "context free" grammar, the set of
18
- parse trees for any piece of a text can depend only on that piece, and
19
- not on the rest of the text (i.e., the piece's context). Context free
20
- grammars are often used to find possible syntactic structures for
21
- sentences. In this context, the leaves of a parse tree are word
22
- tokens; and the node values are phrasal categories, such as ``NP``
23
- and ``VP``.
24
-
25
- The ``CFG`` class is used to encode context free grammars. Each
26
- ``CFG`` consists of a start symbol and a set of productions.
27
- The "start symbol" specifies the root node value for parse trees. For example,
28
- the start symbol for syntactic parsing is usually ``S``. Start
29
- symbols are encoded using the ``Nonterminal`` class, which is discussed
30
- below.
31
-
32
- A Grammar's "productions" specify what parent-child relationships a parse
33
- tree can contain. Each production specifies that a particular
34
- node can be the parent of a particular set of children. For example,
35
- the production ``<S> -> <NP> <VP>`` specifies that an ``S`` node can
36
- be the parent of an ``NP`` node and a ``VP`` node.
37
-
38
- Grammar productions are implemented by the ``Production`` class.
39
- Each ``Production`` consists of a left hand side and a right hand
40
- side. The "left hand side" is a ``Nonterminal`` that specifies the
41
- node type for a potential parent; and the "right hand side" is a list
42
- that specifies allowable children for that parent. This lists
43
- consists of ``Nonterminals`` and text types: each ``Nonterminal``
44
- indicates that the corresponding child may be a ``TreeToken`` with the
45
- specified node type; and each text type indicates that the
46
- corresponding child may be a ``Token`` with the with that type.
47
-
48
- The ``Nonterminal`` class is used to distinguish node values from leaf
49
- values. This prevents the grammar from accidentally using a leaf
50
- value (such as the English word "A") as the node of a subtree. Within
51
- a ``CFG``, all node values are wrapped in the ``Nonterminal``
52
- class. Note, however, that the trees that are specified by the grammar do
53
- *not* include these ``Nonterminal`` wrappers.
54
-
55
- Grammars can also be given a more procedural interpretation. According to
56
- this interpretation, a Grammar specifies any tree structure *tree* that
57
- can be produced by the following procedure:
58
-
59
- | Set tree to the start symbol
60
- | Repeat until tree contains no more nonterminal leaves:
61
- | Choose a production prod with whose left hand side
62
- | lhs is a nonterminal leaf of tree.
63
- | Replace the nonterminal leaf with a subtree, whose node
64
- | value is the value wrapped by the nonterminal lhs, and
65
- | whose children are the right hand side of prod.
66
-
67
- The operation of replacing the left hand side (*lhs*) of a production
68
- with the right hand side (*rhs*) in a tree (*tree*) is known as
69
- "expanding" *lhs* to *rhs* in *tree*.
70
- """
71
- from __future__ import print_function, unicode_literals, division
72
-
73
- import re
74
-
75
- from nltk.util import transitive_closure, invert_graph
76
- from nltk.compat import (string_types, total_ordering, text_type,
77
- python_2_unicode_compatible, unicode_repr)
78
- from nltk.internals import raise_unorderable_types
79
-
80
- from nltk.probability import ImmutableProbabilisticMixIn
81
- from nltk.featstruct import FeatStruct, FeatDict, FeatStructReader, SLASH, TYPE
82
-
83
- #################################################################
84
- # Nonterminal
85
- #################################################################
86
-
87
- @total_ordering
88
- @python_2_unicode_compatible
89
- class Nonterminal(object):
90
- """
91
- A non-terminal symbol for a context free grammar. ``Nonterminal``
92
- is a wrapper class for node values; it is used by ``Production``
93
- objects to distinguish node values from leaf values.
94
- The node value that is wrapped by a ``Nonterminal`` is known as its
95
- "symbol". Symbols are typically strings representing phrasal
96
- categories (such as ``"NP"`` or ``"VP"``). However, more complex
97
- symbol types are sometimes used (e.g., for lexicalized grammars).
98
- Since symbols are node values, they must be immutable and
99
- hashable. Two ``Nonterminals`` are considered equal if their
100
- symbols are equal.
101
-
102
- :see: ``CFG``, ``Production``
103
- :type _symbol: any
104
- :ivar _symbol: The node value corresponding to this
105
- ``Nonterminal``. This value must be immutable and hashable.
106
- """
107
- def __init__(self, symbol):
108
- """
109
- Construct a new non-terminal from the given symbol.
110
-
111
- :type symbol: any
112
- :param symbol: The node value corresponding to this
113
- ``Nonterminal``. This value must be immutable and
114
- hashable.
115
- """
116
- self._symbol = symbol
117
- self._hash = hash(symbol)
118
-
119
- def symbol(self):
120
- """
121
- Return the node value corresponding to this ``Nonterminal``.
122
-
123
- :rtype: (any)
124
- """
125
- return self._symbol
126
-
127
- def __eq__(self, other):
128
- """
129
- Return True if this non-terminal is equal to ``other``. In
130
- particular, return True if ``other`` is a ``Nonterminal``
131
- and this non-terminal's symbol is equal to ``other`` 's symbol.
132
-
133
- :rtype: bool
134
- """
135
- return type(self) == type(other) and self._symbol == other._symbol
136
-
137
- def __ne__(self, other):
138
- return not self == other
139
-
140
- def __lt__(self, other):
141
- if not isinstance(other, Nonterminal):
142
- raise_unorderable_types("<", self, other)
143
- return self._symbol < other._symbol
144
-
145
- def __hash__(self):
146
- return self._hash
147
-
148
- def __repr__(self):
149
- """
150
- Return a string representation for this ``Nonterminal``.
151
-
152
- :rtype: str
153
- """
154
- if isinstance(self._symbol, string_types):
155
- return '%s' % self._symbol
156
- else:
157
- return '%s' % unicode_repr(self._symbol)
158
-
159
- def __str__(self):
160
- """
161
- Return a string representation for this ``Nonterminal``.
162
-
163
- :rtype: str
164
- """
165
- if isinstance(self._symbol, string_types):
166
- return '%s' % self._symbol
167
- else:
168
- return '%s' % unicode_repr(self._symbol)
169
-
170
- def __div__(self, rhs):
171
- """
172
- Return a new nonterminal whose symbol is ``A/B``, where ``A`` is
173
- the symbol for this nonterminal, and ``B`` is the symbol for rhs.
174
-
175
- :param rhs: The nonterminal used to form the right hand side
176
- of the new nonterminal.
177
- :type rhs: Nonterminal
178
- :rtype: Nonterminal
179
- """
180
- return Nonterminal('%s/%s' % (self._symbol, rhs._symbol))
181
-
182
- def nonterminals(symbols):
183
- """
184
- Given a string containing a list of symbol names, return a list of
185
- ``Nonterminals`` constructed from those symbols.
186
-
187
- :param symbols: The symbol name string. This string can be
188
- delimited by either spaces or commas.
189
- :type symbols: str
190
- :return: A list of ``Nonterminals`` constructed from the symbol
191
- names given in ``symbols``. The ``Nonterminals`` are sorted
192
- in the same order as the symbols names.
193
- :rtype: list(Nonterminal)
194
- """
195
- if ',' in symbols: symbol_list = symbols.split(',')
196
- else: symbol_list = symbols.split()
197
- return [Nonterminal(s.strip()) for s in symbol_list]
198
-
199
- class FeatStructNonterminal(FeatDict, Nonterminal):
200
- """A feature structure that's also a nonterminal. It acts as its
201
- own symbol, and automatically freezes itself when hashed."""
202
- def __hash__(self):
203
- self.freeze()
204
- return FeatStruct.__hash__(self)
205
- def symbol(self):
206
- return self
207
-
208
- def is_nonterminal(item):
209
- """
210
- :return: True if the item is a ``Nonterminal``.
211
- :rtype: bool
212
- """
213
- return isinstance(item, Nonterminal)
214
-
215
-
216
- #################################################################
217
- # Terminals
218
- #################################################################
219
-
220
- def is_terminal(item):
221
- """
222
- Return True if the item is a terminal, which currently is
223
- if it is hashable and not a ``Nonterminal``.
224
-
225
- :rtype: bool
226
- """
227
- return hasattr(item, '__hash__') and not isinstance(item, Nonterminal)
228
-
229
-
230
- #################################################################
231
- # Productions
232
- #################################################################
233
-
234
- @total_ordering
235
- @python_2_unicode_compatible
236
- class Production(object):
237
- """
238
- A grammar production. Each production maps a single symbol
239
- on the "left-hand side" to a sequence of symbols on the
240
- "right-hand side". (In the case of context-free productions,
241
- the left-hand side must be a ``Nonterminal``, and the right-hand
242
- side is a sequence of terminals and ``Nonterminals``.)
243
- "terminals" can be any immutable hashable object that is
244
- not a ``Nonterminal``. Typically, terminals are strings
245
- representing words, such as ``"dog"`` or ``"under"``.
246
-
247
- :see: ``CFG``
248
- :see: ``DependencyGrammar``
249
- :see: ``Nonterminal``
250
- :type _lhs: Nonterminal
251
- :ivar _lhs: The left-hand side of the production.
252
- :type _rhs: tuple(Nonterminal, terminal)
253
- :ivar _rhs: The right-hand side of the production.
254
- """
255
-
256
- def __init__(self, lhs, rhs):
257
- """
258
- Construct a new ``Production``.
259
-
260
- :param lhs: The left-hand side of the new ``Production``.
261
- :type lhs: Nonterminal
262
- :param rhs: The right-hand side of the new ``Production``.
263
- :type rhs: sequence(Nonterminal and terminal)
264
- """
265
- if isinstance(rhs, string_types):
266
- raise TypeError('production right hand side should be a list, '
267
- 'not a string')
268
- self._lhs = lhs
269
- self._rhs = tuple(rhs)
270
- self._hash = hash((self._lhs, self._rhs))
271
-
272
- def lhs(self):
273
- """
274
- Return the left-hand side of this ``Production``.
275
-
276
- :rtype: Nonterminal
277
- """
278
- return self._lhs
279
-
280
- def rhs(self):
281
- """
282
- Return the right-hand side of this ``Production``.
283
-
284
- :rtype: sequence(Nonterminal and terminal)
285
- """
286
- return self._rhs
287
-
288
- def __len__(self):
289
- """
290
- Return the length of the right-hand side.
291
-
292
- :rtype: int
293
- """
294
- return len(self._rhs)
295
-
296
- def is_nonlexical(self):
297
- """
298
- Return True if the right-hand side only contains ``Nonterminals``
299
-
300
- :rtype: bool
301
- """
302
- return all(is_nonterminal(n) for n in self._rhs)
303
-
304
- def is_lexical(self):
305
- """
306
- Return True if the right-hand contain at least one terminal token.
307
-
308
- :rtype: bool
309
- """
310
- return not self.is_nonlexical()
311
-
312
- def __str__(self):
313
- """
314
- Return a verbose string representation of the ``Production``.
315
-
316
- :rtype: str
317
- """
318
- result = '%s -> ' % unicode_repr(self._lhs)
319
- result += " ".join(unicode_repr(el) for el in self._rhs)
320
- return result
321
-
322
- def __repr__(self):
323
- """
324
- Return a concise string representation of the ``Production``.
325
-
326
- :rtype: str
327
- """
328
- return '%s' % self
329
-
330
- def __eq__(self, other):
331
- """
332
- Return True if this ``Production`` is equal to ``other``.
333
-
334
- :rtype: bool
335
- """
336
- return (type(self) == type(other) and
337
- self._lhs == other._lhs and
338
- self._rhs == other._rhs)
339
-
340
- def __ne__(self, other):
341
- return not self == other
342
-
343
- def __lt__(self, other):
344
- if not isinstance(other, Production):
345
- raise_unorderable_types("<", self, other)
346
- return (self._lhs, self._rhs) < (other._lhs, other._rhs)
347
-
348
- def __hash__(self):
349
- """
350
- Return a hash value for the ``Production``.
351
-
352
- :rtype: int
353
- """
354
- return self._hash
355
-
356
-
357
- @python_2_unicode_compatible
358
- class DependencyProduction(Production):
359
- """
360
- A dependency grammar production. Each production maps a single
361
- head word to an unordered list of one or more modifier words.
362
- """
363
- def __str__(self):
364
- """
365
- Return a verbose string representation of the ``DependencyProduction``.
366
-
367
- :rtype: str
368
- """
369
- result = '\'%s\' ->' % (self._lhs,)
370
- for elt in self._rhs:
371
- result += ' \'%s\'' % (elt,)
372
- return result
373
-
374
-
375
- @python_2_unicode_compatible
376
- class ProbabilisticProduction(Production, ImmutableProbabilisticMixIn):
377
- """
378
- A probabilistic context free grammar production.
379
- A PCFG ``ProbabilisticProduction`` is essentially just a ``Production`` that
380
- has an associated probability, which represents how likely it is that
381
- this production will be used. In particular, the probability of a
382
- ``ProbabilisticProduction`` records the likelihood that its right-hand side is
383
- the correct instantiation for any given occurrence of its left-hand side.
384
-
385
- :see: ``Production``
386
- """
387
- def __init__(self, lhs, rhs, **prob):
388
- """
389
- Construct a new ``ProbabilisticProduction``.
390
-
391
- :param lhs: The left-hand side of the new ``ProbabilisticProduction``.
392
- :type lhs: Nonterminal
393
- :param rhs: The right-hand side of the new ``ProbabilisticProduction``.
394
- :type rhs: sequence(Nonterminal and terminal)
395
- :param prob: Probability parameters of the new ``ProbabilisticProduction``.
396
- """
397
- ImmutableProbabilisticMixIn.__init__(self, **prob)
398
- Production.__init__(self, lhs, rhs)
399
-
400
- def __str__(self):
401
- return Production.__unicode__(self) + \
402
- (' [1.0]' if (self.prob() == 1.0) else ' [%g]' % self.prob())
403
-
404
- def __eq__(self, other):
405
- return (type(self) == type(other) and
406
- self._lhs == other._lhs and
407
- self._rhs == other._rhs and
408
- self.prob() == other.prob())
409
-
410
- def __ne__(self, other):
411
- return not self == other
412
-
413
- def __hash__(self):
414
- return hash((self._lhs, self._rhs, self.prob()))
415
-
416
- #################################################################
417
- # Grammars
418
- #################################################################
419
-
420
- @python_2_unicode_compatible
421
- class CFG(object):
422
- """
423
- A context-free grammar. A grammar consists of a start state and
424
- a set of productions. The set of terminals and nonterminals is
425
- implicitly specified by the productions.
426
-
427
- If you need efficient key-based access to productions, you
428
- can use a subclass to implement it.
429
- """
430
- def __init__(self, start, productions, calculate_leftcorners=True):
431
- """
432
- Create a new context-free grammar, from the given start state
433
- and set of ``Production``s.
434
-
435
- :param start: The start symbol
436
- :type start: Nonterminal
437
- :param productions: The list of productions that defines the grammar
438
- :type productions: list(Production)
439
- :param calculate_leftcorners: False if we don't want to calculate the
440
- leftcorner relation. In that case, some optimized chart parsers won't work.
441
- :type calculate_leftcorners: bool
442
- """
443
- if not is_nonterminal(start):
444
- raise TypeError("start should be a Nonterminal object,"
445
- " not a %s" % type(start).__name__)
446
-
447
- self._start = start
448
- self._productions = productions
449
- self._categories = set(prod.lhs() for prod in productions)
450
- self._calculate_indexes()
451
- self._calculate_grammar_forms()
452
- if calculate_leftcorners:
453
- self._calculate_leftcorners()
454
-
455
- def _calculate_indexes(self):
456
- self._lhs_index = {}
457
- self._rhs_index = {}
458
- self._empty_index = {}
459
- self._lexical_index = {}
460
- for prod in self._productions:
461
- # Left hand side.
462
- lhs = prod._lhs
463
- if lhs not in self._lhs_index:
464
- self._lhs_index[lhs] = []
465
- self._lhs_index[lhs].append(prod)
466
- if prod._rhs:
467
- # First item in right hand side.
468
- rhs0 = prod._rhs[0]
469
- if rhs0 not in self._rhs_index:
470
- self._rhs_index[rhs0] = []
471
- self._rhs_index[rhs0].append(prod)
472
- else:
473
- # The right hand side is empty.
474
- self._empty_index[prod.lhs()] = prod
475
- # Lexical tokens in the right hand side.
476
- for token in prod._rhs:
477
- if is_terminal(token):
478
- self._lexical_index.setdefault(token, set()).add(prod)
479
-
480
- def _calculate_leftcorners(self):
481
- # Calculate leftcorner relations, for use in optimized parsing.
482
- self._immediate_leftcorner_categories = dict((cat, set([cat])) for cat in self._categories)
483
- self._immediate_leftcorner_words = dict((cat, set()) for cat in self._categories)
484
- for prod in self.productions():
485
- if len(prod) > 0:
486
- cat, left = prod.lhs(), prod.rhs()[0]
487
- if is_nonterminal(left):
488
- self._immediate_leftcorner_categories[cat].add(left)
489
- else:
490
- self._immediate_leftcorner_words[cat].add(left)
491
-
492
- lc = transitive_closure(self._immediate_leftcorner_categories, reflexive=True)
493
- self._leftcorners = lc
494
- self._leftcorner_parents = invert_graph(lc)
495
-
496
- nr_leftcorner_categories = sum(map(len, self._immediate_leftcorner_categories.values()))
497
- nr_leftcorner_words = sum(map(len, self._immediate_leftcorner_words.values()))
498
- if nr_leftcorner_words > nr_leftcorner_categories > 10000:
499
- # If the grammar is big, the leftcorner-word dictionary will be too large.
500
- # In that case it is better to calculate the relation on demand.
501
- self._leftcorner_words = None
502
- return
503
-
504
- self._leftcorner_words = {}
505
- for cat in self._leftcorners:
506
- lefts = self._leftcorners[cat]
507
- lc = self._leftcorner_words[cat] = set()
508
- for left in lefts:
509
- lc.update(self._immediate_leftcorner_words.get(left, set()))
510
-
511
- @classmethod
512
- def fromstring(cls, input, encoding=None):
513
- """
514
- Return the ``CFG`` corresponding to the input string(s).
515
-
516
- :param input: a grammar, either in the form of a string or as a list of strings.
517
- """
518
- start, productions = read_grammar(input, standard_nonterm_parser,
519
- encoding=encoding)
520
- return CFG(start, productions)
521
-
522
- def start(self):
523
- """
524
- Return the start symbol of the grammar
525
-
526
- :rtype: Nonterminal
527
- """
528
- return self._start
529
-
530
- # tricky to balance readability and efficiency here!
531
- # can't use set operations as they don't preserve ordering
532
- def productions(self, lhs=None, rhs=None, empty=False):
533
- """
534
- Return the grammar productions, filtered by the left-hand side
535
- or the first item in the right-hand side.
536
-
537
- :param lhs: Only return productions with the given left-hand side.
538
- :param rhs: Only return productions with the given first item
539
- in the right-hand side.
540
- :param empty: Only return productions with an empty right-hand side.
541
- :return: A list of productions matching the given constraints.
542
- :rtype: list(Production)
543
- """
544
- if rhs and empty:
545
- raise ValueError("You cannot select empty and non-empty "
546
- "productions at the same time.")
547
-
548
- # no constraints so return everything
549
- if not lhs and not rhs:
550
- if not empty:
551
- return self._productions
552
- else:
553
- return self._empty_index.values()
554
-
555
- # only lhs specified so look up its index
556
- elif lhs and not rhs:
557
- if not empty:
558
- return self._lhs_index.get(lhs, [])
559
- elif lhs in self._empty_index:
560
- return [self._empty_index[lhs]]
561
- else:
562
- return []
563
-
564
- # only rhs specified so look up its index
565
- elif rhs and not lhs:
566
- return self._rhs_index.get(rhs, [])
567
-
568
- # intersect
569
- else:
570
- return [prod for prod in self._lhs_index.get(lhs, [])
571
- if prod in self._rhs_index.get(rhs, [])]
572
-
573
- def leftcorners(self, cat):
574
- """
575
- Return the set of all nonterminals that the given nonterminal
576
- can start with, including itself.
577
-
578
- This is the reflexive, transitive closure of the immediate
579
- leftcorner relation: (A > B) iff (A -> B beta)
580
-
581
- :param cat: the parent of the leftcorners
582
- :type cat: Nonterminal
583
- :return: the set of all leftcorners
584
- :rtype: set(Nonterminal)
585
- """
586
- return self._leftcorners.get(cat, set([cat]))
587
-
588
- def is_leftcorner(self, cat, left):
589
- """
590
- True if left is a leftcorner of cat, where left can be a
591
- terminal or a nonterminal.
592
-
593
- :param cat: the parent of the leftcorner
594
- :type cat: Nonterminal
595
- :param left: the suggested leftcorner
596
- :type left: Terminal or Nonterminal
597
- :rtype: bool
598
- """
599
- if is_nonterminal(left):
600
- return left in self.leftcorners(cat)
601
- elif self._leftcorner_words:
602
- return left in self._leftcorner_words.get(cat, set())
603
- else:
604
- return any(left in self._immediate_leftcorner_words.get(parent, set())
605
- for parent in self.leftcorners(cat))
606
-
607
- def leftcorner_parents(self, cat):
608
- """
609
- Return the set of all nonterminals for which the given category
610
- is a left corner. This is the inverse of the leftcorner relation.
611
-
612
- :param cat: the suggested leftcorner
613
- :type cat: Nonterminal
614
- :return: the set of all parents to the leftcorner
615
- :rtype: set(Nonterminal)
616
- """
617
- return self._leftcorner_parents.get(cat, set([cat]))
618
-
619
- def check_coverage(self, tokens):
620
- """
621
- Check whether the grammar rules cover the given list of tokens.
622
- If not, then raise an exception.
623
-
624
- :type tokens: list(str)
625
- """
626
- missing = [tok for tok in tokens
627
- if not self._lexical_index.get(tok)]
628
- if missing:
629
- missing = ', '.join('%r' % (w,) for w in missing)
630
- raise ValueError("Grammar does not cover some of the "
631
- "input words: %r." % missing)
632
-
633
- def _calculate_grammar_forms(self):
634
- """
635
- Pre-calculate of which form(s) the grammar is.
636
- """
637
- prods = self._productions
638
- self._is_lexical = all(p.is_lexical() for p in prods)
639
- self._is_nonlexical = all(p.is_nonlexical() for p in prods
640
- if len(p) != 1)
641
- self._min_len = min(len(p) for p in prods)
642
- self._max_len = max(len(p) for p in prods)
643
- self._all_unary_are_lexical = all(p.is_lexical() for p in prods
644
- if len(p) == 1)
645
-
646
- def is_lexical(self):
647
- """
648
- Return True if all productions are lexicalised.
649
- """
650
- return self._is_lexical
651
-
652
- def is_nonlexical(self):
653
- """
654
- Return True if all lexical rules are "preterminals", that is,
655
- unary rules which can be separated in a preprocessing step.
656
-
657
- This means that all productions are of the forms
658
- A -> B1 ... Bn (n>=0), or A -> "s".
659
-
660
- Note: is_lexical() and is_nonlexical() are not opposites.
661
- There are grammars which are neither, and grammars which are both.
662
- """
663
- return self._is_nonlexical
664
-
665
- def min_len(self):
666
- """
667
- Return the right-hand side length of the shortest grammar production.
668
- """
669
- return self._min_len
670
-
671
- def max_len(self):
672
- """
673
- Return the right-hand side length of the longest grammar production.
674
- """
675
- return self._max_len
676
-
677
- def is_nonempty(self):
678
- """
679
- Return True if there are no empty productions.
680
- """
681
- return self._min_len > 0
682
-
683
- def is_binarised(self):
684
- """
685
- Return True if all productions are at most binary.
686
- Note that there can still be empty and unary productions.
687
- """
688
- return self._max_len <= 2
689
-
690
- def is_flexible_chomsky_normal_form(self):
691
- """
692
- Return True if all productions are of the forms
693
- A -> B C, A -> B, or A -> "s".
694
- """
695
- return self.is_nonempty() and self.is_nonlexical() and self.is_binarised()
696
-
697
- def is_chomsky_normal_form(self):
698
- """
699
- Return True if the grammar is of Chomsky Normal Form, i.e. all productions
700
- are of the form A -> B C, or A -> "s".
701
- """
702
- return (self.is_flexible_chomsky_normal_form() and
703
- self._all_unary_are_lexical)
704
-
705
- def __repr__(self):
706
- return '<Grammar with %d productions>' % len(self._productions)
707
-
708
- def __str__(self):
709
- result = 'Grammar with %d productions' % len(self._productions)
710
- result += ' (start state = %r)' % self._start
711
- for production in self._productions:
712
- result += '\n %s' % production
713
- return result
714
-
715
-
716
- class FeatureGrammar(CFG):
717
- """
718
- A feature-based grammar. This is equivalent to a
719
- ``CFG`` whose nonterminals are all
720
- ``FeatStructNonterminal``.
721
-
722
- A grammar consists of a start state and a set of
723
- productions. The set of terminals and nonterminals
724
- is implicitly specified by the productions.
725
- """
726
- def __init__(self, start, productions):
727
- """
728
- Create a new feature-based grammar, from the given start
729
- state and set of ``Productions``.
730
-
731
- :param start: The start symbol
732
- :type start: FeatStructNonterminal
733
- :param productions: The list of productions that defines the grammar
734
- :type productions: list(Production)
735
- """
736
- CFG.__init__(self, start, productions)
737
-
738
- # The difference with CFG is that the productions are
739
- # indexed on the TYPE feature of the nonterminals.
740
- # This is calculated by the method _get_type_if_possible().
741
-
742
- def _calculate_indexes(self):
743
- self._lhs_index = {}
744
- self._rhs_index = {}
745
- self._empty_index = {}
746
- self._empty_productions = []
747
- self._lexical_index = {}
748
- for prod in self._productions:
749
- # Left hand side.
750
- lhs = self._get_type_if_possible(prod._lhs)
751
- if lhs not in self._lhs_index:
752
- self._lhs_index[lhs] = []
753
- self._lhs_index[lhs].append(prod)
754
- if prod._rhs:
755
- # First item in right hand side.
756
- rhs0 = self._get_type_if_possible(prod._rhs[0])
757
- if rhs0 not in self._rhs_index:
758
- self._rhs_index[rhs0] = []
759
- self._rhs_index[rhs0].append(prod)
760
- else:
761
- # The right hand side is empty.
762
- if lhs not in self._empty_index:
763
- self._empty_index[lhs] = []
764
- self._empty_index[lhs].append(prod)
765
- self._empty_productions.append(prod)
766
- # Lexical tokens in the right hand side.
767
- for token in prod._rhs:
768
- if is_terminal(token):
769
- self._lexical_index.setdefault(token, set()).add(prod)
770
-
771
- @classmethod
772
- def fromstring(cls, input, features=None, logic_parser=None, fstruct_reader=None,
773
- encoding=None):
774
- """
775
- Return a feature structure based ``FeatureGrammar``.
776
-
777
- :param input: a grammar, either in the form of a string or else
778
- as a list of strings.
779
- :param features: a tuple of features (default: SLASH, TYPE)
780
- :param logic_parser: a parser for lambda-expressions,
781
- by default, ``LogicParser()``
782
- :param fstruct_reader: a feature structure parser
783
- (only if features and logic_parser is None)
784
- """
785
- if features is None:
786
- features = (SLASH, TYPE)
787
-
788
- if fstruct_reader is None:
789
- fstruct_reader = FeatStructReader(features, FeatStructNonterminal,
790
- logic_parser=logic_parser)
791
- elif logic_parser is not None:
792
- raise Exception('\'logic_parser\' and \'fstruct_reader\' must '
793
- 'not both be set')
794
-
795
- start, productions = read_grammar(input, fstruct_reader.read_partial,
796
- encoding=encoding)
797
- return FeatureGrammar(start, productions)
798
-
799
-
800
- def productions(self, lhs=None, rhs=None, empty=False):
801
- """
802
- Return the grammar productions, filtered by the left-hand side
803
- or the first item in the right-hand side.
804
-
805
- :param lhs: Only return productions with the given left-hand side.
806
- :param rhs: Only return productions with the given first item
807
- in the right-hand side.
808
- :param empty: Only return productions with an empty right-hand side.
809
- :rtype: list(Production)
810
- """
811
- if rhs and empty:
812
- raise ValueError("You cannot select empty and non-empty "
813
- "productions at the same time.")
814
-
815
- # no constraints so return everything
816
- if not lhs and not rhs:
817
- if empty:
818
- return self._empty_productions
819
- else:
820
- return self._productions
821
-
822
- # only lhs specified so look up its index
823
- elif lhs and not rhs:
824
- if empty:
825
- return self._empty_index.get(self._get_type_if_possible(lhs), [])
826
- else:
827
- return self._lhs_index.get(self._get_type_if_possible(lhs), [])
828
-
829
- # only rhs specified so look up its index
830
- elif rhs and not lhs:
831
- return self._rhs_index.get(self._get_type_if_possible(rhs), [])
832
-
833
- # intersect
834
- else:
835
- return [prod for prod in self._lhs_index.get(self._get_type_if_possible(lhs), [])
836
- if prod in self._rhs_index.get(self._get_type_if_possible(rhs), [])]
837
-
838
- def leftcorners(self, cat):
839
- """
840
- Return the set of all words that the given category can start with.
841
- Also called the "first set" in compiler construction.
842
- """
843
- raise NotImplementedError("Not implemented yet")
844
-
845
- def leftcorner_parents(self, cat):
846
- """
847
- Return the set of all categories for which the given category
848
- is a left corner.
849
- """
850
- raise NotImplementedError("Not implemented yet")
851
-
852
- def _get_type_if_possible(self, item):
853
- """
854
- Helper function which returns the ``TYPE`` feature of the ``item``,
855
- if it exists, otherwise it returns the ``item`` itself
856
- """
857
- if isinstance(item, dict) and TYPE in item:
858
- return FeatureValueType(item[TYPE])
859
- else:
860
- return item
861
-
862
- @total_ordering
863
- @python_2_unicode_compatible
864
- class FeatureValueType(object):
865
- """
866
- A helper class for ``FeatureGrammars``, designed to be different
867
- from ordinary strings. This is to stop the ``FeatStruct``
868
- ``FOO[]`` from being compare equal to the terminal "FOO".
869
- """
870
- def __init__(self, value):
871
- self._value = value
872
- self._hash = hash(value)
873
-
874
- def __repr__(self):
875
- return '<%s>' % self._value
876
-
877
- def __eq__(self, other):
878
- return type(self) == type(other) and self._value == other._value
879
-
880
- def __ne__(self, other):
881
- return not self == other
882
-
883
- def __lt__(self, other):
884
- if not isinstance(other, FeatureValueType):
885
- raise_unorderable_types("<", self, other)
886
- return self._value < other._value
887
-
888
- def __hash__(self):
889
- return self._hash
890
-
891
-
892
- @python_2_unicode_compatible
893
- class DependencyGrammar(object):
894
- """
895
- A dependency grammar. A DependencyGrammar consists of a set of
896
- productions. Each production specifies a head/modifier relationship
897
- between a pair of words.
898
- """
899
- def __init__(self, productions):
900
- """
901
- Create a new dependency grammar, from the set of ``Productions``.
902
-
903
- :param productions: The list of productions that defines the grammar
904
- :type productions: list(Production)
905
- """
906
- self._productions = productions
907
-
908
- @classmethod
909
- def fromstring(cls, input):
910
- productions = []
911
- for linenum, line in enumerate(input.split('\n')):
912
- line = line.strip()
913
- if line.startswith('#') or line=='': continue
914
- try: productions += _read_dependency_production(line)
915
- except ValueError:
916
- raise ValueError('Unable to parse line %s: %s' % (linenum, line))
917
- if len(productions) == 0:
918
- raise ValueError('No productions found!')
919
- return DependencyGrammar(productions)
920
-
921
- def contains(self, head, mod):
922
- """
923
- :param head: A head word.
924
- :type head: str
925
- :param mod: A mod word, to test as a modifier of 'head'.
926
- :type mod: str
927
-
928
- :return: true if this ``DependencyGrammar`` contains a
929
- ``DependencyProduction`` mapping 'head' to 'mod'.
930
- :rtype: bool
931
- """
932
- for production in self._productions:
933
- for possibleMod in production._rhs:
934
- if(production._lhs == head and possibleMod == mod):
935
- return True
936
- return False
937
-
938
- def __contains__(self, head, mod):
939
- """
940
- Return True if this ``DependencyGrammar`` contains a
941
- ``DependencyProduction`` mapping 'head' to 'mod'.
942
-
943
- :param head: A head word.
944
- :type head: str
945
- :param mod: A mod word, to test as a modifier of 'head'.
946
- :type mod: str
947
- :rtype: bool
948
- """
949
- for production in self._productions:
950
- for possibleMod in production._rhs:
951
- if(production._lhs == head and possibleMod == mod):
952
- return True
953
- return False
954
-
955
- # # should be rewritten, the set comp won't work in all comparisons
956
- # def contains_exactly(self, head, modlist):
957
- # for production in self._productions:
958
- # if(len(production._rhs) == len(modlist)):
959
- # if(production._lhs == head):
960
- # set1 = Set(production._rhs)
961
- # set2 = Set(modlist)
962
- # if(set1 == set2):
963
- # return True
964
- # return False
965
-
966
-
967
- def __str__(self):
968
- """
969
- Return a verbose string representation of the ``DependencyGrammar``
970
-
971
- :rtype: str
972
- """
973
- str = 'Dependency grammar with %d productions' % len(self._productions)
974
- for production in self._productions:
975
- str += '\n %s' % production
976
- return str
977
-
978
- def __repr__(self):
979
- """
980
- Return a concise string representation of the ``DependencyGrammar``
981
- """
982
- return 'Dependency grammar with %d productions' % len(self._productions)
983
-
984
-
985
- @python_2_unicode_compatible
986
- class ProbabilisticDependencyGrammar(object):
987
- """
988
-
989
- """
990
-
991
- def __init__(self, productions, events, tags):
992
- self._productions = productions
993
- self._events = events
994
- self._tags = tags
995
-
996
- def contains(self, head, mod):
997
- """
998
- Return True if this ``DependencyGrammar`` contains a
999
- ``DependencyProduction`` mapping 'head' to 'mod'.
1000
-
1001
- :param head: A head word.
1002
- :type head: str
1003
- :param mod: A mod word, to test as a modifier of 'head'.
1004
- :type mod: str
1005
- :rtype: bool
1006
- """
1007
- for production in self._productions:
1008
- for possibleMod in production._rhs:
1009
- if(production._lhs == head and possibleMod == mod):
1010
- return True
1011
- return False
1012
-
1013
- def __str__(self):
1014
- """
1015
- Return a verbose string representation of the ``ProbabilisticDependencyGrammar``
1016
-
1017
- :rtype: str
1018
- """
1019
- str = 'Statistical dependency grammar with %d productions' % len(self._productions)
1020
- for production in self._productions:
1021
- str += '\n %s' % production
1022
- str += '\nEvents:'
1023
- for event in self._events:
1024
- str += '\n %d:%s' % (self._events[event], event)
1025
- str += '\nTags:'
1026
- for tag_word in self._tags:
1027
- str += '\n %s:\t(%s)' % (tag_word, self._tags[tag_word])
1028
- return str
1029
-
1030
- def __repr__(self):
1031
- """
1032
- Return a concise string representation of the ``ProbabilisticDependencyGrammar``
1033
- """
1034
- return 'Statistical Dependency grammar with %d productions' % len(self._productions)
1035
-
1036
-
1037
- class PCFG(CFG):
1038
- """
1039
- A probabilistic context-free grammar. A PCFG consists of a
1040
- start state and a set of productions with probabilities. The set of
1041
- terminals and nonterminals is implicitly specified by the productions.
1042
-
1043
- PCFG productions use the ``ProbabilisticProduction`` class.
1044
- ``PCFGs`` impose the constraint that the set of productions with
1045
- any given left-hand-side must have probabilities that sum to 1
1046
- (allowing for a small margin of error).
1047
-
1048
- If you need efficient key-based access to productions, you can use
1049
- a subclass to implement it.
1050
-
1051
- :type EPSILON: float
1052
- :cvar EPSILON: The acceptable margin of error for checking that
1053
- productions with a given left-hand side have probabilities
1054
- that sum to 1.
1055
- """
1056
- EPSILON = 0.01
1057
-
1058
- def __init__(self, start, productions, calculate_leftcorners=True):
1059
- """
1060
- Create a new context-free grammar, from the given start state
1061
- and set of ``ProbabilisticProductions``.
1062
-
1063
- :param start: The start symbol
1064
- :type start: Nonterminal
1065
- :param productions: The list of productions that defines the grammar
1066
- :type productions: list(Production)
1067
- :raise ValueError: if the set of productions with any left-hand-side
1068
- do not have probabilities that sum to a value within
1069
- EPSILON of 1.
1070
- :param calculate_leftcorners: False if we don't want to calculate the
1071
- leftcorner relation. In that case, some optimized chart parsers won't work.
1072
- :type calculate_leftcorners: bool
1073
- """
1074
- CFG.__init__(self, start, productions, calculate_leftcorners)
1075
-
1076
- # Make sure that the probabilities sum to one.
1077
- probs = {}
1078
- for production in productions:
1079
- probs[production.lhs()] = (probs.get(production.lhs(), 0) +
1080
- production.prob())
1081
- for (lhs, p) in probs.items():
1082
- if not ((1-PCFG.EPSILON) < p <
1083
- (1+PCFG.EPSILON)):
1084
- raise ValueError("Productions for %r do not sum to 1" % lhs)
1085
-
1086
-
1087
- @classmethod
1088
- def fromstring(cls, input, encoding=None):
1089
- """
1090
- Return a probabilistic ``PCFG`` corresponding to the
1091
- input string(s).
1092
-
1093
- :param input: a grammar, either in the form of a string or else
1094
- as a list of strings.
1095
- """
1096
- start, productions = read_grammar(input, standard_nonterm_parser,
1097
- probabilistic=True, encoding=encoding)
1098
- return PCFG(start, productions)
1099
-
1100
-
1101
- #################################################################
1102
- # Inducing Grammars
1103
- #################################################################
1104
-
1105
- # Contributed by Nathan Bodenstab <bodenstab@cslu.ogi.edu>
1106
-
1107
- def induce_pcfg(start, productions):
1108
- """
1109
- Induce a PCFG grammar from a list of productions.
1110
-
1111
- The probability of a production A -> B C in a PCFG is:
1112
-
1113
- | count(A -> B C)
1114
- | P(B, C | A) = --------------- where \* is any right hand side
1115
- | count(A -> \*)
1116
-
1117
- :param start: The start symbol
1118
- :type start: Nonterminal
1119
- :param productions: The list of productions that defines the grammar
1120
- :type productions: list(Production)
1121
- """
1122
- # Production count: the number of times a given production occurs
1123
- pcount = {}
1124
-
1125
- # LHS-count: counts the number of times a given lhs occurs
1126
- lcount = {}
1127
-
1128
- for prod in productions:
1129
- lcount[prod.lhs()] = lcount.get(prod.lhs(), 0) + 1
1130
- pcount[prod] = pcount.get(prod, 0) + 1
1131
-
1132
- prods = [ProbabilisticProduction(p.lhs(), p.rhs(),
1133
- prob=pcount[p] / lcount[p.lhs()])
1134
- for p in pcount]
1135
- return PCFG(start, prods)
1136
-
1137
-
1138
- #################################################################
1139
- # Helper functions for reading productions
1140
- #################################################################
1141
-
1142
- def _read_cfg_production(input):
1143
- """
1144
- Return a list of context-free ``Productions``.
1145
- """
1146
- return _read_production(input, standard_nonterm_parser)
1147
-
1148
- def _read_pcfg_production(input):
1149
- """
1150
- Return a list of PCFG ``ProbabilisticProductions``.
1151
- """
1152
- return _read_production(input, standard_nonterm_parser, probabilistic=True)
1153
-
1154
- def _read_fcfg_production(input, fstruct_reader):
1155
- """
1156
- Return a list of feature-based ``Productions``.
1157
- """
1158
- return _read_production(input, fstruct_reader)
1159
-
1160
-
1161
- # Parsing generic grammars
1162
-
1163
- _ARROW_RE = re.compile(r'\s* -> \s*', re.VERBOSE)
1164
- _PROBABILITY_RE = re.compile(r'( \[ [\d\.]+ \] ) \s*', re.VERBOSE)
1165
- _TERMINAL_RE = re.compile(r'( "[^"]+" | \'[^\']+\' ) \s*', re.VERBOSE)
1166
- _DISJUNCTION_RE = re.compile(r'\| \s*', re.VERBOSE)
1167
-
1168
- def _read_production(line, nonterm_parser, probabilistic=False):
1169
- """
1170
- Parse a grammar rule, given as a string, and return
1171
- a list of productions.
1172
- """
1173
- pos = 0
1174
-
1175
- # Parse the left-hand side.
1176
- lhs, pos = nonterm_parser(line, pos)
1177
-
1178
- # Skip over the arrow.
1179
- m = _ARROW_RE.match(line, pos)
1180
- if not m: raise ValueError('Expected an arrow')
1181
- pos = m.end()
1182
-
1183
- # Parse the right hand side.
1184
- probabilities = [0.0]
1185
- rhsides = [[]]
1186
- while pos < len(line):
1187
- # Probability.
1188
- m = _PROBABILITY_RE.match(line, pos)
1189
- if probabilistic and m:
1190
- pos = m.end()
1191
- probabilities[-1] = float(m.group(1)[1:-1])
1192
- if probabilities[-1] > 1.0:
1193
- raise ValueError('Production probability %f, '
1194
- 'should not be greater than 1.0' %
1195
- (probabilities[-1],))
1196
-
1197
- # String -- add terminal.
1198
- elif line[pos] in "\'\"":
1199
- m = _TERMINAL_RE.match(line, pos)
1200
- if not m: raise ValueError('Unterminated string')
1201
- rhsides[-1].append(m.group(1)[1:-1])
1202
- pos = m.end()
1203
-
1204
- # Vertical bar -- start new rhside.
1205
- elif line[pos] == '|':
1206
- m = _DISJUNCTION_RE.match(line, pos)
1207
- probabilities.append(0.0)
1208
- rhsides.append([])
1209
- pos = m.end()
1210
-
1211
- # Anything else -- nonterminal.
1212
- else:
1213
- nonterm, pos = nonterm_parser(line, pos)
1214
- rhsides[-1].append(nonterm)
1215
-
1216
- if probabilistic:
1217
- return [ProbabilisticProduction(lhs, rhs, prob=probability)
1218
- for (rhs, probability) in zip(rhsides, probabilities)]
1219
- else:
1220
- return [Production(lhs, rhs) for rhs in rhsides]
1221
-
1222
-
1223
- #################################################################
1224
- # Reading Phrase Structure Grammars
1225
- #################################################################
1226
-
1227
- def read_grammar(input, nonterm_parser, probabilistic=False, encoding=None):
1228
- """
1229
- Return a pair consisting of a starting category and a list of
1230
- ``Productions``.
1231
-
1232
- :param input: a grammar, either in the form of a string or else
1233
- as a list of strings.
1234
- :param nonterm_parser: a function for parsing nonterminals.
1235
- It should take a ``(string, position)`` as argument and
1236
- return a ``(nonterminal, position)`` as result.
1237
- :param probabilistic: are the grammar rules probabilistic?
1238
- :type probabilistic: bool
1239
- :param encoding: the encoding of the grammar, if it is a binary string
1240
- :type encoding: str
1241
- """
1242
- if encoding is not None:
1243
- input = input.decode(encoding)
1244
- if isinstance(input, string_types):
1245
- lines = input.split('\n')
1246
- else:
1247
- lines = input
1248
-
1249
- start = None
1250
- productions = []
1251
- continue_line = ''
1252
- for linenum, line in enumerate(lines):
1253
- line = continue_line + line.strip()
1254
- if line.startswith('#') or line=='': continue
1255
- if line.endswith('\\'):
1256
- continue_line = line[:-1].rstrip()+' '
1257
- continue
1258
- continue_line = ''
1259
- try:
1260
- if line[0] == '%':
1261
- directive, args = line[1:].split(None, 1)
1262
- if directive == 'start':
1263
- start, pos = nonterm_parser(args, 0)
1264
- if pos != len(args):
1265
- raise ValueError('Bad argument to start directive')
1266
- else:
1267
- raise ValueError('Bad directive')
1268
- else:
1269
- # expand out the disjunctions on the RHS
1270
- productions += _read_production(line, nonterm_parser, probabilistic)
1271
- except ValueError as e:
1272
- raise ValueError('Unable to parse line %s: %s\n%s' %
1273
- (linenum+1, line, e))
1274
-
1275
- if not productions:
1276
- raise ValueError('No productions found!')
1277
- if not start:
1278
- start = productions[0].lhs()
1279
- return (start, productions)
1280
-
1281
- _STANDARD_NONTERM_RE = re.compile('( [\w/][\w/^<>-]* ) \s*', re.VERBOSE)
1282
-
1283
- def standard_nonterm_parser(string, pos):
1284
- m = _STANDARD_NONTERM_RE.match(string, pos)
1285
- if not m: raise ValueError('Expected a nonterminal, found: '
1286
- + string[pos:])
1287
- return (Nonterminal(m.group(1)), m.end())
1288
-
1289
-
1290
- #################################################################
1291
- # Reading Dependency Grammars
1292
- #################################################################
1293
-
1294
- _READ_DG_RE = re.compile(r'''^\s* # leading whitespace
1295
- ('[^']+')\s* # single-quoted lhs
1296
- (?:[-=]+>)\s* # arrow
1297
- (?:( # rhs:
1298
- "[^"]+" # doubled-quoted terminal
1299
- | '[^']+' # single-quoted terminal
1300
- | \| # disjunction
1301
- )
1302
- \s*) # trailing space
1303
- *$''', # zero or more copies
1304
- re.VERBOSE)
1305
- _SPLIT_DG_RE = re.compile(r'''('[^']'|[-=]+>|"[^"]+"|'[^']+'|\|)''')
1306
-
1307
- def _read_dependency_production(s):
1308
- if not _READ_DG_RE.match(s):
1309
- raise ValueError('Bad production string')
1310
- pieces = _SPLIT_DG_RE.split(s)
1311
- pieces = [p for i,p in enumerate(pieces) if i%2==1]
1312
- lhside = pieces[0].strip('\'\"')
1313
- rhsides = [[]]
1314
- for piece in pieces[2:]:
1315
- if piece == '|':
1316
- rhsides.append([])
1317
- else:
1318
- rhsides[-1].append(piece.strip('\'\"'))
1319
- return [DependencyProduction(lhside, rhside) for rhside in rhsides]
1320
-
1321
-
1322
- #################################################################
1323
- # Demonstration
1324
- #################################################################
1325
-
1326
- def cfg_demo():
1327
- """
1328
- A demonstration showing how ``CFGs`` can be created and used.
1329
- """
1330
-
1331
- from nltk import nonterminals, Production, CFG
1332
-
1333
- # Create some nonterminals
1334
- S, NP, VP, PP = nonterminals('S, NP, VP, PP')
1335
- N, V, P, Det = nonterminals('N, V, P, Det')
1336
- VP_slash_NP = VP/NP
1337
-
1338
- print('Some nonterminals:', [S, NP, VP, PP, N, V, P, Det, VP/NP])
1339
- print(' S.symbol() =>', repr(S.symbol()))
1340
- print()
1341
-
1342
- print(Production(S, [NP]))
1343
-
1344
- # Create some Grammar Productions
1345
- grammar = CFG.fromstring("""
1346
- S -> NP VP
1347
- PP -> P NP
1348
- NP -> Det N | NP PP
1349
- VP -> V NP | VP PP
1350
- Det -> 'a' | 'the'
1351
- N -> 'dog' | 'cat'
1352
- V -> 'chased' | 'sat'
1353
- P -> 'on' | 'in'
1354
- """)
1355
-
1356
- print('A Grammar:', repr(grammar))
1357
- print(' grammar.start() =>', repr(grammar.start()))
1358
- print(' grammar.productions() =>', end=' ')
1359
- # Use string.replace(...) is to line-wrap the output.
1360
- print(repr(grammar.productions()).replace(',', ',\n'+' '*25))
1361
- print()
1362
-
1363
- toy_pcfg1 = PCFG.fromstring("""
1364
- S -> NP VP [1.0]
1365
- NP -> Det N [0.5] | NP PP [0.25] | 'John' [0.1] | 'I' [0.15]
1366
- Det -> 'the' [0.8] | 'my' [0.2]
1367
- N -> 'man' [0.5] | 'telescope' [0.5]
1368
- VP -> VP PP [0.1] | V NP [0.7] | V [0.2]
1369
- V -> 'ate' [0.35] | 'saw' [0.65]
1370
- PP -> P NP [1.0]
1371
- P -> 'with' [0.61] | 'under' [0.39]
1372
- """)
1373
-
1374
- toy_pcfg2 = PCFG.fromstring("""
1375
- S -> NP VP [1.0]
1376
- VP -> V NP [.59]
1377
- VP -> V [.40]
1378
- VP -> VP PP [.01]
1379
- NP -> Det N [.41]
1380
- NP -> Name [.28]
1381
- NP -> NP PP [.31]
1382
- PP -> P NP [1.0]
1383
- V -> 'saw' [.21]
1384
- V -> 'ate' [.51]
1385
- V -> 'ran' [.28]
1386
- N -> 'boy' [.11]
1387
- N -> 'cookie' [.12]
1388
- N -> 'table' [.13]
1389
- N -> 'telescope' [.14]
1390
- N -> 'hill' [.5]
1391
- Name -> 'Jack' [.52]
1392
- Name -> 'Bob' [.48]
1393
- P -> 'with' [.61]
1394
- P -> 'under' [.39]
1395
- Det -> 'the' [.41]
1396
- Det -> 'a' [.31]
1397
- Det -> 'my' [.28]
1398
- """)
1399
-
1400
- def pcfg_demo():
1401
- """
1402
- A demonstration showing how a ``PCFG`` can be created and used.
1403
- """
1404
-
1405
- from nltk.corpus import treebank
1406
- from nltk import treetransforms
1407
- from nltk import induce_pcfg
1408
- from nltk.parse import pchart
1409
-
1410
- pcfg_prods = toy_pcfg1.productions()
1411
-
1412
- pcfg_prod = pcfg_prods[2]
1413
- print('A PCFG production:', repr(pcfg_prod))
1414
- print(' pcfg_prod.lhs() =>', repr(pcfg_prod.lhs()))
1415
- print(' pcfg_prod.rhs() =>', repr(pcfg_prod.rhs()))
1416
- print(' pcfg_prod.prob() =>', repr(pcfg_prod.prob()))
1417
- print()
1418
-
1419
- grammar = toy_pcfg2
1420
- print('A PCFG grammar:', repr(grammar))
1421
- print(' grammar.start() =>', repr(grammar.start()))
1422
- print(' grammar.productions() =>', end=' ')
1423
- # Use .replace(...) is to line-wrap the output.
1424
- print(repr(grammar.productions()).replace(',', ',\n'+' '*26))
1425
- print()
1426
-
1427
- # extract productions from three trees and induce the PCFG
1428
- print("Induce PCFG grammar from treebank data:")
1429
-
1430
- productions = []
1431
- item = treebank._fileids[0]
1432
- for tree in treebank.parsed_sents(item)[:3]:
1433
- # perform optional tree transformations, e.g.:
1434
- tree.collapse_unary(collapsePOS = False)
1435
- tree.chomsky_normal_form(horzMarkov = 2)
1436
-
1437
- productions += tree.productions()
1438
-
1439
- S = Nonterminal('S')
1440
- grammar = induce_pcfg(S, productions)
1441
- print(grammar)
1442
- print()
1443
-
1444
- print("Parse sentence using induced grammar:")
1445
-
1446
- parser = pchart.InsideChartParser(grammar)
1447
- parser.trace(3)
1448
-
1449
- # doesn't work as tokens are different:
1450
- #sent = treebank.tokenized('wsj_0001.mrg')[0]
1451
-
1452
- sent = treebank.parsed_sents(item)[0].leaves()
1453
- print(sent)
1454
- for parse in parser.parse(sent):
1455
- print(parse)
1456
-
1457
- def fcfg_demo():
1458
- import nltk.data
1459
- g = nltk.data.load('grammars/book_grammars/feat0.fcfg')
1460
- print(g)
1461
- print()
1462
-
1463
- def dg_demo():
1464
- """
1465
- A demonstration showing the creation and inspection of a
1466
- ``DependencyGrammar``.
1467
- """
1468
- grammar = DependencyGrammar.fromstring("""
1469
- 'scratch' -> 'cats' | 'walls'
1470
- 'walls' -> 'the'
1471
- 'cats' -> 'the'
1472
- """)
1473
- print(grammar)
1474
-
1475
- def sdg_demo():
1476
- """
1477
- A demonstration of how to read a string representation of
1478
- a CoNLL format dependency tree.
1479
- """
1480
- from nltk.parse import DependencyGraph
1481
-
1482
- dg = DependencyGraph("""
1483
- 1 Ze ze Pron Pron per|3|evofmv|nom 2 su _ _
1484
- 2 had heb V V trans|ovt|1of2of3|ev 0 ROOT _ _
1485
- 3 met met Prep Prep voor 8 mod _ _
1486
- 4 haar haar Pron Pron bez|3|ev|neut|attr 5 det _ _
1487
- 5 moeder moeder N N soort|ev|neut 3 obj1 _ _
1488
- 6 kunnen kan V V hulp|ott|1of2of3|mv 2 vc _ _
1489
- 7 gaan ga V V hulp|inf 6 vc _ _
1490
- 8 winkelen winkel V V intrans|inf 11 cnj _ _
1491
- 9 , , Punc Punc komma 8 punct _ _
1492
- 10 zwemmen zwem V V intrans|inf 11 cnj _ _
1493
- 11 of of Conj Conj neven 7 vc _ _
1494
- 12 terrassen terras N N soort|mv|neut 11 cnj _ _
1495
- 13 . . Punc Punc punt 12 punct _ _
1496
- """)
1497
- tree = dg.tree()
1498
- print(tree.pprint())
1499
-
1500
- def demo():
1501
- cfg_demo()
1502
- pcfg_demo()
1503
- fcfg_demo()
1504
- dg_demo()
1505
- sdg_demo()
1506
-
1507
- if __name__ == '__main__':
1508
- demo()
1509
-
1510
- __all__ = ['Nonterminal', 'nonterminals',
1511
- 'CFG', 'Production',
1512
- 'PCFG', 'ProbabilisticProduction',
1513
- 'DependencyGrammar', 'DependencyProduction',
1514
- 'ProbabilisticDependencyGrammar',
1515
- 'induce_pcfg', 'read_grammar']
1516
-
1
+ # -*- coding: utf-8 -*-
2
+ # Natural Language Toolkit: Context Free Grammars
3
+ #
4
+ # Copyright (C) 2001-2018 NLTK Project
5
+ # Author: Steven Bird <stevenbird1@gmail.com>
6
+ # Edward Loper <edloper@gmail.com>
7
+ # Jason Narad <jason.narad@gmail.com>
8
+ # Peter Ljunglöf <peter.ljunglof@heatherleaf.se>
9
+ # URL: <http://nltk.org/>
10
+ # For license information, see LICENSE.TXT
11
+ #
12
+
13
+ """
14
+ Basic data classes for representing context free grammars. A
15
+ "grammar" specifies which trees can represent the structure of a
16
+ given text. Each of these trees is called a "parse tree" for the
17
+ text (or simply a "parse"). In a "context free" grammar, the set of
18
+ parse trees for any piece of a text can depend only on that piece, and
19
+ not on the rest of the text (i.e., the piece's context). Context free
20
+ grammars are often used to find possible syntactic structures for
21
+ sentences. In this context, the leaves of a parse tree are word
22
+ tokens; and the node values are phrasal categories, such as ``NP``
23
+ and ``VP``.
24
+
25
+ The ``CFG`` class is used to encode context free grammars. Each
26
+ ``CFG`` consists of a start symbol and a set of productions.
27
+ The "start symbol" specifies the root node value for parse trees. For example,
28
+ the start symbol for syntactic parsing is usually ``S``. Start
29
+ symbols are encoded using the ``Nonterminal`` class, which is discussed
30
+ below.
31
+
32
+ A Grammar's "productions" specify what parent-child relationships a parse
33
+ tree can contain. Each production specifies that a particular
34
+ node can be the parent of a particular set of children. For example,
35
+ the production ``<S> -> <NP> <VP>`` specifies that an ``S`` node can
36
+ be the parent of an ``NP`` node and a ``VP`` node.
37
+
38
+ Grammar productions are implemented by the ``Production`` class.
39
+ Each ``Production`` consists of a left hand side and a right hand
40
+ side. The "left hand side" is a ``Nonterminal`` that specifies the
41
+ node type for a potential parent; and the "right hand side" is a list
42
+ that specifies allowable children for that parent. This lists
43
+ consists of ``Nonterminals`` and text types: each ``Nonterminal``
44
+ indicates that the corresponding child may be a ``TreeToken`` with the
45
+ specified node type; and each text type indicates that the
46
+ corresponding child may be a ``Token`` with the with that type.
47
+
48
+ The ``Nonterminal`` class is used to distinguish node values from leaf
49
+ values. This prevents the grammar from accidentally using a leaf
50
+ value (such as the English word "A") as the node of a subtree. Within
51
+ a ``CFG``, all node values are wrapped in the ``Nonterminal``
52
+ class. Note, however, that the trees that are specified by the grammar do
53
+ *not* include these ``Nonterminal`` wrappers.
54
+
55
+ Grammars can also be given a more procedural interpretation. According to
56
+ this interpretation, a Grammar specifies any tree structure *tree* that
57
+ can be produced by the following procedure:
58
+
59
+ | Set tree to the start symbol
60
+ | Repeat until tree contains no more nonterminal leaves:
61
+ | Choose a production prod with whose left hand side
62
+ | lhs is a nonterminal leaf of tree.
63
+ | Replace the nonterminal leaf with a subtree, whose node
64
+ | value is the value wrapped by the nonterminal lhs, and
65
+ | whose children are the right hand side of prod.
66
+
67
+ The operation of replacing the left hand side (*lhs*) of a production
68
+ with the right hand side (*rhs*) in a tree (*tree*) is known as
69
+ "expanding" *lhs* to *rhs* in *tree*.
70
+ """
71
+ from __future__ import print_function, unicode_literals, division
72
+
73
+ import re
74
+ from functools import total_ordering
75
+
76
+ from six import string_types
77
+
78
+ from nltk.util import transitive_closure, invert_graph
79
+ from nltk.compat import python_2_unicode_compatible, unicode_repr
80
+ from nltk.internals import raise_unorderable_types
81
+
82
+ from nltk.probability import ImmutableProbabilisticMixIn
83
+ from nltk.featstruct import FeatStruct, FeatDict, FeatStructReader, SLASH, TYPE
84
+
85
+
86
+ #################################################################
87
+ # Nonterminal
88
+ #################################################################
89
+
90
+ @total_ordering
91
+ @python_2_unicode_compatible
92
+ class Nonterminal(object):
93
+ """
94
+ A non-terminal symbol for a context free grammar. ``Nonterminal``
95
+ is a wrapper class for node values; it is used by ``Production``
96
+ objects to distinguish node values from leaf values.
97
+ The node value that is wrapped by a ``Nonterminal`` is known as its
98
+ "symbol". Symbols are typically strings representing phrasal
99
+ categories (such as ``"NP"`` or ``"VP"``). However, more complex
100
+ symbol types are sometimes used (e.g., for lexicalized grammars).
101
+ Since symbols are node values, they must be immutable and
102
+ hashable. Two ``Nonterminals`` are considered equal if their
103
+ symbols are equal.
104
+
105
+ :see: ``CFG``, ``Production``
106
+ :type _symbol: any
107
+ :ivar _symbol: The node value corresponding to this
108
+ ``Nonterminal``. This value must be immutable and hashable.
109
+ """
110
+
111
+ def __init__(self, symbol):
112
+ """
113
+ Construct a new non-terminal from the given symbol.
114
+
115
+ :type symbol: any
116
+ :param symbol: The node value corresponding to this
117
+ ``Nonterminal``. This value must be immutable and
118
+ hashable.
119
+ """
120
+ self._symbol = symbol
121
+ self._hash = hash(symbol)
122
+
123
+ def symbol(self):
124
+ """
125
+ Return the node value corresponding to this ``Nonterminal``.
126
+
127
+ :rtype: (any)
128
+ """
129
+ return self._symbol
130
+
131
+ def __eq__(self, other):
132
+ """
133
+ Return True if this non-terminal is equal to ``other``. In
134
+ particular, return True if ``other`` is a ``Nonterminal``
135
+ and this non-terminal's symbol is equal to ``other`` 's symbol.
136
+
137
+ :rtype: bool
138
+ """
139
+ return type(self) == type(other) and self._symbol == other._symbol
140
+
141
+ def __ne__(self, other):
142
+ return not self == other
143
+
144
+ def __lt__(self, other):
145
+ if not isinstance(other, Nonterminal):
146
+ raise_unorderable_types("<", self, other)
147
+ return self._symbol < other._symbol
148
+
149
+ def __hash__(self):
150
+ return self._hash
151
+
152
+ def __repr__(self):
153
+ """
154
+ Return a string representation for this ``Nonterminal``.
155
+
156
+ :rtype: str
157
+ """
158
+ if isinstance(self._symbol, string_types):
159
+ return '%s' % self._symbol
160
+ else:
161
+ return '%s' % unicode_repr(self._symbol)
162
+
163
+ def __str__(self):
164
+ """
165
+ Return a string representation for this ``Nonterminal``.
166
+
167
+ :rtype: str
168
+ """
169
+ if isinstance(self._symbol, string_types):
170
+ return '%s' % self._symbol
171
+ else:
172
+ return '%s' % unicode_repr(self._symbol)
173
+
174
+ def __div__(self, rhs):
175
+ """
176
+ Return a new nonterminal whose symbol is ``A/B``, where ``A`` is
177
+ the symbol for this nonterminal, and ``B`` is the symbol for rhs.
178
+
179
+ :param rhs: The nonterminal used to form the right hand side
180
+ of the new nonterminal.
181
+ :type rhs: Nonterminal
182
+ :rtype: Nonterminal
183
+ """
184
+ return Nonterminal('%s/%s' % (self._symbol, rhs._symbol))
185
+
186
+ def __truediv__(self, rhs):
187
+ """
188
+ Return a new nonterminal whose symbol is ``A/B``, where ``A`` is
189
+ the symbol for this nonterminal, and ``B`` is the symbol for rhs.
190
+ This function allows use of the slash ``/`` operator with
191
+ the future import of division.
192
+
193
+ :param rhs: The nonterminal used to form the right hand side
194
+ of the new nonterminal.
195
+ :type rhs: Nonterminal
196
+ :rtype: Nonterminal
197
+ """
198
+ return self.__div__(rhs)
199
+
200
+
201
+ def nonterminals(symbols):
202
+ """
203
+ Given a string containing a list of symbol names, return a list of
204
+ ``Nonterminals`` constructed from those symbols.
205
+
206
+ :param symbols: The symbol name string. This string can be
207
+ delimited by either spaces or commas.
208
+ :type symbols: str
209
+ :return: A list of ``Nonterminals`` constructed from the symbol
210
+ names given in ``symbols``. The ``Nonterminals`` are sorted
211
+ in the same order as the symbols names.
212
+ :rtype: list(Nonterminal)
213
+ """
214
+ if ',' in symbols:
215
+ symbol_list = symbols.split(',')
216
+ else:
217
+ symbol_list = symbols.split()
218
+ return [Nonterminal(s.strip()) for s in symbol_list]
219
+
220
+
221
+ class FeatStructNonterminal(FeatDict, Nonterminal):
222
+ """A feature structure that's also a nonterminal. It acts as its
223
+ own symbol, and automatically freezes itself when hashed."""
224
+
225
+ def __hash__(self):
226
+ self.freeze()
227
+ return FeatStruct.__hash__(self)
228
+
229
+ def symbol(self):
230
+ return self
231
+
232
+
233
+ def is_nonterminal(item):
234
+ """
235
+ :return: True if the item is a ``Nonterminal``.
236
+ :rtype: bool
237
+ """
238
+ return isinstance(item, Nonterminal)
239
+
240
+
241
+ #################################################################
242
+ # Terminals
243
+ #################################################################
244
+
245
+ def is_terminal(item):
246
+ """
247
+ Return True if the item is a terminal, which currently is
248
+ if it is hashable and not a ``Nonterminal``.
249
+
250
+ :rtype: bool
251
+ """
252
+ return hasattr(item, '__hash__') and not isinstance(item, Nonterminal)
253
+
254
+
255
+ #################################################################
256
+ # Productions
257
+ #################################################################
258
+
259
+ @total_ordering
260
+ @python_2_unicode_compatible
261
+ class Production(object):
262
+ """
263
+ A grammar production. Each production maps a single symbol
264
+ on the "left-hand side" to a sequence of symbols on the
265
+ "right-hand side". (In the case of context-free productions,
266
+ the left-hand side must be a ``Nonterminal``, and the right-hand
267
+ side is a sequence of terminals and ``Nonterminals``.)
268
+ "terminals" can be any immutable hashable object that is
269
+ not a ``Nonterminal``. Typically, terminals are strings
270
+ representing words, such as ``"dog"`` or ``"under"``.
271
+
272
+ :see: ``CFG``
273
+ :see: ``DependencyGrammar``
274
+ :see: ``Nonterminal``
275
+ :type _lhs: Nonterminal
276
+ :ivar _lhs: The left-hand side of the production.
277
+ :type _rhs: tuple(Nonterminal, terminal)
278
+ :ivar _rhs: The right-hand side of the production.
279
+ """
280
+
281
+ def __init__(self, lhs, rhs):
282
+ """
283
+ Construct a new ``Production``.
284
+
285
+ :param lhs: The left-hand side of the new ``Production``.
286
+ :type lhs: Nonterminal
287
+ :param rhs: The right-hand side of the new ``Production``.
288
+ :type rhs: sequence(Nonterminal and terminal)
289
+ """
290
+ if isinstance(rhs, string_types):
291
+ raise TypeError('production right hand side should be a list, '
292
+ 'not a string')
293
+ self._lhs = lhs
294
+ self._rhs = tuple(rhs)
295
+ self._hash = hash((self._lhs, self._rhs))
296
+
297
+ def lhs(self):
298
+ """
299
+ Return the left-hand side of this ``Production``.
300
+
301
+ :rtype: Nonterminal
302
+ """
303
+ return self._lhs
304
+
305
+ def rhs(self):
306
+ """
307
+ Return the right-hand side of this ``Production``.
308
+
309
+ :rtype: sequence(Nonterminal and terminal)
310
+ """
311
+ return self._rhs
312
+
313
+ def __len__(self):
314
+ """
315
+ Return the length of the right-hand side.
316
+
317
+ :rtype: int
318
+ """
319
+ return len(self._rhs)
320
+
321
+ def is_nonlexical(self):
322
+ """
323
+ Return True if the right-hand side only contains ``Nonterminals``
324
+
325
+ :rtype: bool
326
+ """
327
+ return all(is_nonterminal(n) for n in self._rhs)
328
+
329
+ def is_lexical(self):
330
+ """
331
+ Return True if the right-hand contain at least one terminal token.
332
+
333
+ :rtype: bool
334
+ """
335
+ return not self.is_nonlexical()
336
+
337
+ def __str__(self):
338
+ """
339
+ Return a verbose string representation of the ``Production``.
340
+
341
+ :rtype: str
342
+ """
343
+ result = '%s -> ' % unicode_repr(self._lhs)
344
+ result += " ".join(unicode_repr(el) for el in self._rhs)
345
+ return result
346
+
347
+ def __repr__(self):
348
+ """
349
+ Return a concise string representation of the ``Production``.
350
+
351
+ :rtype: str
352
+ """
353
+ return '%s' % self
354
+
355
+ def __eq__(self, other):
356
+ """
357
+ Return True if this ``Production`` is equal to ``other``.
358
+
359
+ :rtype: bool
360
+ """
361
+ return (type(self) == type(other) and
362
+ self._lhs == other._lhs and
363
+ self._rhs == other._rhs)
364
+
365
+ def __ne__(self, other):
366
+ return not self == other
367
+
368
+ def __lt__(self, other):
369
+ if not isinstance(other, Production):
370
+ raise_unorderable_types("<", self, other)
371
+ return (self._lhs, self._rhs) < (other._lhs, other._rhs)
372
+
373
+ def __hash__(self):
374
+ """
375
+ Return a hash value for the ``Production``.
376
+
377
+ :rtype: int
378
+ """
379
+ return self._hash
380
+
381
+
382
+ @python_2_unicode_compatible
383
+ class DependencyProduction(Production):
384
+ """
385
+ A dependency grammar production. Each production maps a single
386
+ head word to an unordered list of one or more modifier words.
387
+ """
388
+
389
+ def __str__(self):
390
+ """
391
+ Return a verbose string representation of the ``DependencyProduction``.
392
+
393
+ :rtype: str
394
+ """
395
+ result = '\'%s\' ->' % (self._lhs,)
396
+ for elt in self._rhs:
397
+ result += ' \'%s\'' % (elt,)
398
+ return result
399
+
400
+
401
+ @python_2_unicode_compatible
402
+ class ProbabilisticProduction(Production, ImmutableProbabilisticMixIn):
403
+ """
404
+ A probabilistic context free grammar production.
405
+ A PCFG ``ProbabilisticProduction`` is essentially just a ``Production`` that
406
+ has an associated probability, which represents how likely it is that
407
+ this production will be used. In particular, the probability of a
408
+ ``ProbabilisticProduction`` records the likelihood that its right-hand side is
409
+ the correct instantiation for any given occurrence of its left-hand side.
410
+
411
+ :see: ``Production``
412
+ """
413
+
414
+ def __init__(self, lhs, rhs, **prob):
415
+ """
416
+ Construct a new ``ProbabilisticProduction``.
417
+
418
+ :param lhs: The left-hand side of the new ``ProbabilisticProduction``.
419
+ :type lhs: Nonterminal
420
+ :param rhs: The right-hand side of the new ``ProbabilisticProduction``.
421
+ :type rhs: sequence(Nonterminal and terminal)
422
+ :param prob: Probability parameters of the new ``ProbabilisticProduction``.
423
+ """
424
+ ImmutableProbabilisticMixIn.__init__(self, **prob)
425
+ Production.__init__(self, lhs, rhs)
426
+
427
+ def __str__(self):
428
+ return Production.__unicode__(self) + \
429
+ (' [1.0]' if (self.prob() == 1.0) else ' [%g]' % self.prob())
430
+
431
+ def __eq__(self, other):
432
+ return (type(self) == type(other) and
433
+ self._lhs == other._lhs and
434
+ self._rhs == other._rhs and
435
+ self.prob() == other.prob())
436
+
437
+ def __ne__(self, other):
438
+ return not self == other
439
+
440
+ def __hash__(self):
441
+ return hash((self._lhs, self._rhs, self.prob()))
442
+
443
+
444
+ #################################################################
445
+ # Grammars
446
+ #################################################################
447
+
448
+ @python_2_unicode_compatible
449
+ class CFG(object):
450
+ """
451
+ A context-free grammar. A grammar consists of a start state and
452
+ a set of productions. The set of terminals and nonterminals is
453
+ implicitly specified by the productions.
454
+
455
+ If you need efficient key-based access to productions, you
456
+ can use a subclass to implement it.
457
+ """
458
+
459
+ def __init__(self, start, productions, calculate_leftcorners=True):
460
+ """
461
+ Create a new context-free grammar, from the given start state
462
+ and set of ``Production``s.
463
+
464
+ :param start: The start symbol
465
+ :type start: Nonterminal
466
+ :param productions: The list of productions that defines the grammar
467
+ :type productions: list(Production)
468
+ :param calculate_leftcorners: False if we don't want to calculate the
469
+ leftcorner relation. In that case, some optimized chart parsers won't work.
470
+ :type calculate_leftcorners: bool
471
+ """
472
+ if not is_nonterminal(start):
473
+ raise TypeError("start should be a Nonterminal object,"
474
+ " not a %s" % type(start).__name__)
475
+
476
+ self._start = start
477
+ self._productions = productions
478
+ self._categories = set(prod.lhs() for prod in productions)
479
+ self._calculate_indexes()
480
+ self._calculate_grammar_forms()
481
+ if calculate_leftcorners:
482
+ self._calculate_leftcorners()
483
+
484
+ def _calculate_indexes(self):
485
+ self._lhs_index = {}
486
+ self._rhs_index = {}
487
+ self._empty_index = {}
488
+ self._lexical_index = {}
489
+ for prod in self._productions:
490
+ # Left hand side.
491
+ lhs = prod._lhs
492
+ if lhs not in self._lhs_index:
493
+ self._lhs_index[lhs] = []
494
+ self._lhs_index[lhs].append(prod)
495
+ if prod._rhs:
496
+ # First item in right hand side.
497
+ rhs0 = prod._rhs[0]
498
+ if rhs0 not in self._rhs_index:
499
+ self._rhs_index[rhs0] = []
500
+ self._rhs_index[rhs0].append(prod)
501
+ else:
502
+ # The right hand side is empty.
503
+ self._empty_index[prod.lhs()] = prod
504
+ # Lexical tokens in the right hand side.
505
+ for token in prod._rhs:
506
+ if is_terminal(token):
507
+ self._lexical_index.setdefault(token, set()).add(prod)
508
+
509
+ def _calculate_leftcorners(self):
510
+ # Calculate leftcorner relations, for use in optimized parsing.
511
+ self._immediate_leftcorner_categories = dict((cat, set([cat])) for cat in self._categories)
512
+ self._immediate_leftcorner_words = dict((cat, set()) for cat in self._categories)
513
+ for prod in self.productions():
514
+ if len(prod) > 0:
515
+ cat, left = prod.lhs(), prod.rhs()[0]
516
+ if is_nonterminal(left):
517
+ self._immediate_leftcorner_categories[cat].add(left)
518
+ else:
519
+ self._immediate_leftcorner_words[cat].add(left)
520
+
521
+ lc = transitive_closure(self._immediate_leftcorner_categories, reflexive=True)
522
+ self._leftcorners = lc
523
+ self._leftcorner_parents = invert_graph(lc)
524
+
525
+ nr_leftcorner_categories = sum(map(len, self._immediate_leftcorner_categories.values()))
526
+ nr_leftcorner_words = sum(map(len, self._immediate_leftcorner_words.values()))
527
+ if nr_leftcorner_words > nr_leftcorner_categories > 10000:
528
+ # If the grammar is big, the leftcorner-word dictionary will be too large.
529
+ # In that case it is better to calculate the relation on demand.
530
+ self._leftcorner_words = None
531
+ return
532
+
533
+ self._leftcorner_words = {}
534
+ for cat in self._leftcorners:
535
+ lefts = self._leftcorners[cat]
536
+ lc = self._leftcorner_words[cat] = set()
537
+ for left in lefts:
538
+ lc.update(self._immediate_leftcorner_words.get(left, set()))
539
+
540
+ @classmethod
541
+ def fromstring(cls, input, encoding=None):
542
+ """
543
+ Return the grammar instance corresponding to the input string(s).
544
+
545
+ :param input: a grammar, either in the form of a string or as a list of strings.
546
+ """
547
+ start, productions = read_grammar(input, standard_nonterm_parser,
548
+ encoding=encoding)
549
+ return cls(start, productions)
550
+
551
+ def start(self):
552
+ """
553
+ Return the start symbol of the grammar
554
+
555
+ :rtype: Nonterminal
556
+ """
557
+ return self._start
558
+
559
+ # tricky to balance readability and efficiency here!
560
+ # can't use set operations as they don't preserve ordering
561
+ def productions(self, lhs=None, rhs=None, empty=False):
562
+ """
563
+ Return the grammar productions, filtered by the left-hand side
564
+ or the first item in the right-hand side.
565
+
566
+ :param lhs: Only return productions with the given left-hand side.
567
+ :param rhs: Only return productions with the given first item
568
+ in the right-hand side.
569
+ :param empty: Only return productions with an empty right-hand side.
570
+ :return: A list of productions matching the given constraints.
571
+ :rtype: list(Production)
572
+ """
573
+ if rhs and empty:
574
+ raise ValueError("You cannot select empty and non-empty "
575
+ "productions at the same time.")
576
+
577
+ # no constraints so return everything
578
+ if not lhs and not rhs:
579
+ if not empty:
580
+ return self._productions
581
+ else:
582
+ return self._empty_index.values()
583
+
584
+ # only lhs specified so look up its index
585
+ elif lhs and not rhs:
586
+ if not empty:
587
+ return self._lhs_index.get(lhs, [])
588
+ elif lhs in self._empty_index:
589
+ return [self._empty_index[lhs]]
590
+ else:
591
+ return []
592
+
593
+ # only rhs specified so look up its index
594
+ elif rhs and not lhs:
595
+ return self._rhs_index.get(rhs, [])
596
+
597
+ # intersect
598
+ else:
599
+ return [prod for prod in self._lhs_index.get(lhs, [])
600
+ if prod in self._rhs_index.get(rhs, [])]
601
+
602
+ def leftcorners(self, cat):
603
+ """
604
+ Return the set of all nonterminals that the given nonterminal
605
+ can start with, including itself.
606
+
607
+ This is the reflexive, transitive closure of the immediate
608
+ leftcorner relation: (A > B) iff (A -> B beta)
609
+
610
+ :param cat: the parent of the leftcorners
611
+ :type cat: Nonterminal
612
+ :return: the set of all leftcorners
613
+ :rtype: set(Nonterminal)
614
+ """
615
+ return self._leftcorners.get(cat, set([cat]))
616
+
617
+ def is_leftcorner(self, cat, left):
618
+ """
619
+ True if left is a leftcorner of cat, where left can be a
620
+ terminal or a nonterminal.
621
+
622
+ :param cat: the parent of the leftcorner
623
+ :type cat: Nonterminal
624
+ :param left: the suggested leftcorner
625
+ :type left: Terminal or Nonterminal
626
+ :rtype: bool
627
+ """
628
+ if is_nonterminal(left):
629
+ return left in self.leftcorners(cat)
630
+ elif self._leftcorner_words:
631
+ return left in self._leftcorner_words.get(cat, set())
632
+ else:
633
+ return any(left in self._immediate_leftcorner_words.get(parent, set())
634
+ for parent in self.leftcorners(cat))
635
+
636
+ def leftcorner_parents(self, cat):
637
+ """
638
+ Return the set of all nonterminals for which the given category
639
+ is a left corner. This is the inverse of the leftcorner relation.
640
+
641
+ :param cat: the suggested leftcorner
642
+ :type cat: Nonterminal
643
+ :return: the set of all parents to the leftcorner
644
+ :rtype: set(Nonterminal)
645
+ """
646
+ return self._leftcorner_parents.get(cat, set([cat]))
647
+
648
+ def check_coverage(self, tokens):
649
+ """
650
+ Check whether the grammar rules cover the given list of tokens.
651
+ If not, then raise an exception.
652
+
653
+ :type tokens: list(str)
654
+ """
655
+ missing = [tok for tok in tokens
656
+ if not self._lexical_index.get(tok)]
657
+ if missing:
658
+ missing = ', '.join('%r' % (w,) for w in missing)
659
+ raise ValueError("Grammar does not cover some of the "
660
+ "input words: %r." % missing)
661
+
662
+ def _calculate_grammar_forms(self):
663
+ """
664
+ Pre-calculate of which form(s) the grammar is.
665
+ """
666
+ prods = self._productions
667
+ self._is_lexical = all(p.is_lexical() for p in prods)
668
+ self._is_nonlexical = all(p.is_nonlexical() for p in prods
669
+ if len(p) != 1)
670
+ self._min_len = min(len(p) for p in prods)
671
+ self._max_len = max(len(p) for p in prods)
672
+ self._all_unary_are_lexical = all(p.is_lexical() for p in prods
673
+ if len(p) == 1)
674
+
675
+ def is_lexical(self):
676
+ """
677
+ Return True if all productions are lexicalised.
678
+ """
679
+ return self._is_lexical
680
+
681
+ def is_nonlexical(self):
682
+ """
683
+ Return True if all lexical rules are "preterminals", that is,
684
+ unary rules which can be separated in a preprocessing step.
685
+
686
+ This means that all productions are of the forms
687
+ A -> B1 ... Bn (n>=0), or A -> "s".
688
+
689
+ Note: is_lexical() and is_nonlexical() are not opposites.
690
+ There are grammars which are neither, and grammars which are both.
691
+ """
692
+ return self._is_nonlexical
693
+
694
+ def min_len(self):
695
+ """
696
+ Return the right-hand side length of the shortest grammar production.
697
+ """
698
+ return self._min_len
699
+
700
+ def max_len(self):
701
+ """
702
+ Return the right-hand side length of the longest grammar production.
703
+ """
704
+ return self._max_len
705
+
706
+ def is_nonempty(self):
707
+ """
708
+ Return True if there are no empty productions.
709
+ """
710
+ return self._min_len > 0
711
+
712
+ def is_binarised(self):
713
+ """
714
+ Return True if all productions are at most binary.
715
+ Note that there can still be empty and unary productions.
716
+ """
717
+ return self._max_len <= 2
718
+
719
+ def is_flexible_chomsky_normal_form(self):
720
+ """
721
+ Return True if all productions are of the forms
722
+ A -> B C, A -> B, or A -> "s".
723
+ """
724
+ return self.is_nonempty() and self.is_nonlexical() and self.is_binarised()
725
+
726
+ def is_chomsky_normal_form(self):
727
+ """
728
+ Return True if the grammar is of Chomsky Normal Form, i.e. all productions
729
+ are of the form A -> B C, or A -> "s".
730
+ """
731
+ return (self.is_flexible_chomsky_normal_form() and
732
+ self._all_unary_are_lexical)
733
+
734
+ def __repr__(self):
735
+ return '<Grammar with %d productions>' % len(self._productions)
736
+
737
+ def __str__(self):
738
+ result = 'Grammar with %d productions' % len(self._productions)
739
+ result += ' (start state = %r)' % self._start
740
+ for production in self._productions:
741
+ result += '\n %s' % production
742
+ return result
743
+
744
+
745
+ class FeatureGrammar(CFG):
746
+ """
747
+ A feature-based grammar. This is equivalent to a
748
+ ``CFG`` whose nonterminals are all
749
+ ``FeatStructNonterminal``.
750
+
751
+ A grammar consists of a start state and a set of
752
+ productions. The set of terminals and nonterminals
753
+ is implicitly specified by the productions.
754
+ """
755
+
756
+ def __init__(self, start, productions):
757
+ """
758
+ Create a new feature-based grammar, from the given start
759
+ state and set of ``Productions``.
760
+
761
+ :param start: The start symbol
762
+ :type start: FeatStructNonterminal
763
+ :param productions: The list of productions that defines the grammar
764
+ :type productions: list(Production)
765
+ """
766
+ CFG.__init__(self, start, productions)
767
+
768
+ # The difference with CFG is that the productions are
769
+ # indexed on the TYPE feature of the nonterminals.
770
+ # This is calculated by the method _get_type_if_possible().
771
+
772
+ def _calculate_indexes(self):
773
+ self._lhs_index = {}
774
+ self._rhs_index = {}
775
+ self._empty_index = {}
776
+ self._empty_productions = []
777
+ self._lexical_index = {}
778
+ for prod in self._productions:
779
+ # Left hand side.
780
+ lhs = self._get_type_if_possible(prod._lhs)
781
+ if lhs not in self._lhs_index:
782
+ self._lhs_index[lhs] = []
783
+ self._lhs_index[lhs].append(prod)
784
+ if prod._rhs:
785
+ # First item in right hand side.
786
+ rhs0 = self._get_type_if_possible(prod._rhs[0])
787
+ if rhs0 not in self._rhs_index:
788
+ self._rhs_index[rhs0] = []
789
+ self._rhs_index[rhs0].append(prod)
790
+ else:
791
+ # The right hand side is empty.
792
+ if lhs not in self._empty_index:
793
+ self._empty_index[lhs] = []
794
+ self._empty_index[lhs].append(prod)
795
+ self._empty_productions.append(prod)
796
+ # Lexical tokens in the right hand side.
797
+ for token in prod._rhs:
798
+ if is_terminal(token):
799
+ self._lexical_index.setdefault(token, set()).add(prod)
800
+
801
+ @classmethod
802
+ def fromstring(cls, input, features=None, logic_parser=None, fstruct_reader=None,
803
+ encoding=None):
804
+ """
805
+ Return a feature structure based grammar.
806
+
807
+ :param input: a grammar, either in the form of a string or else
808
+ as a list of strings.
809
+ :param features: a tuple of features (default: SLASH, TYPE)
810
+ :param logic_parser: a parser for lambda-expressions,
811
+ by default, ``LogicParser()``
812
+ :param fstruct_reader: a feature structure parser
813
+ (only if features and logic_parser is None)
814
+ """
815
+ if features is None:
816
+ features = (SLASH, TYPE)
817
+
818
+ if fstruct_reader is None:
819
+ fstruct_reader = FeatStructReader(features, FeatStructNonterminal,
820
+ logic_parser=logic_parser)
821
+ elif logic_parser is not None:
822
+ raise Exception('\'logic_parser\' and \'fstruct_reader\' must '
823
+ 'not both be set')
824
+
825
+ start, productions = read_grammar(input, fstruct_reader.read_partial,
826
+ encoding=encoding)
827
+ return cls(start, productions)
828
+
829
+ def productions(self, lhs=None, rhs=None, empty=False):
830
+ """
831
+ Return the grammar productions, filtered by the left-hand side
832
+ or the first item in the right-hand side.
833
+
834
+ :param lhs: Only return productions with the given left-hand side.
835
+ :param rhs: Only return productions with the given first item
836
+ in the right-hand side.
837
+ :param empty: Only return productions with an empty right-hand side.
838
+ :rtype: list(Production)
839
+ """
840
+ if rhs and empty:
841
+ raise ValueError("You cannot select empty and non-empty "
842
+ "productions at the same time.")
843
+
844
+ # no constraints so return everything
845
+ if not lhs and not rhs:
846
+ if empty:
847
+ return self._empty_productions
848
+ else:
849
+ return self._productions
850
+
851
+ # only lhs specified so look up its index
852
+ elif lhs and not rhs:
853
+ if empty:
854
+ return self._empty_index.get(self._get_type_if_possible(lhs), [])
855
+ else:
856
+ return self._lhs_index.get(self._get_type_if_possible(lhs), [])
857
+
858
+ # only rhs specified so look up its index
859
+ elif rhs and not lhs:
860
+ return self._rhs_index.get(self._get_type_if_possible(rhs), [])
861
+
862
+ # intersect
863
+ else:
864
+ return [prod for prod in self._lhs_index.get(self._get_type_if_possible(lhs), [])
865
+ if prod in self._rhs_index.get(self._get_type_if_possible(rhs), [])]
866
+
867
+ def leftcorners(self, cat):
868
+ """
869
+ Return the set of all words that the given category can start with.
870
+ Also called the "first set" in compiler construction.
871
+ """
872
+ raise NotImplementedError("Not implemented yet")
873
+
874
+ def leftcorner_parents(self, cat):
875
+ """
876
+ Return the set of all categories for which the given category
877
+ is a left corner.
878
+ """
879
+ raise NotImplementedError("Not implemented yet")
880
+
881
+ def _get_type_if_possible(self, item):
882
+ """
883
+ Helper function which returns the ``TYPE`` feature of the ``item``,
884
+ if it exists, otherwise it returns the ``item`` itself
885
+ """
886
+ if isinstance(item, dict) and TYPE in item:
887
+ return FeatureValueType(item[TYPE])
888
+ else:
889
+ return item
890
+
891
+
892
+ @total_ordering
893
+ @python_2_unicode_compatible
894
+ class FeatureValueType(object):
895
+ """
896
+ A helper class for ``FeatureGrammars``, designed to be different
897
+ from ordinary strings. This is to stop the ``FeatStruct``
898
+ ``FOO[]`` from being compare equal to the terminal "FOO".
899
+ """
900
+
901
+ def __init__(self, value):
902
+ self._value = value
903
+ self._hash = hash(value)
904
+
905
+ def __repr__(self):
906
+ return '<%s>' % self._value
907
+
908
+ def __eq__(self, other):
909
+ return type(self) == type(other) and self._value == other._value
910
+
911
+ def __ne__(self, other):
912
+ return not self == other
913
+
914
+ def __lt__(self, other):
915
+ if not isinstance(other, FeatureValueType):
916
+ raise_unorderable_types("<", self, other)
917
+ return self._value < other._value
918
+
919
+ def __hash__(self):
920
+ return self._hash
921
+
922
+
923
+ @python_2_unicode_compatible
924
+ class DependencyGrammar(object):
925
+ """
926
+ A dependency grammar. A DependencyGrammar consists of a set of
927
+ productions. Each production specifies a head/modifier relationship
928
+ between a pair of words.
929
+ """
930
+
931
+ def __init__(self, productions):
932
+ """
933
+ Create a new dependency grammar, from the set of ``Productions``.
934
+
935
+ :param productions: The list of productions that defines the grammar
936
+ :type productions: list(Production)
937
+ """
938
+ self._productions = productions
939
+
940
+ @classmethod
941
+ def fromstring(cls, input):
942
+ productions = []
943
+ for linenum, line in enumerate(input.split('\n')):
944
+ line = line.strip()
945
+ if line.startswith('#') or line == '': continue
946
+ try:
947
+ productions += _read_dependency_production(line)
948
+ except ValueError:
949
+ raise ValueError('Unable to parse line %s: %s' % (linenum, line))
950
+ if len(productions) == 0:
951
+ raise ValueError('No productions found!')
952
+ return cls(productions)
953
+
954
+ def contains(self, head, mod):
955
+ """
956
+ :param head: A head word.
957
+ :type head: str
958
+ :param mod: A mod word, to test as a modifier of 'head'.
959
+ :type mod: str
960
+
961
+ :return: true if this ``DependencyGrammar`` contains a
962
+ ``DependencyProduction`` mapping 'head' to 'mod'.
963
+ :rtype: bool
964
+ """
965
+ for production in self._productions:
966
+ for possibleMod in production._rhs:
967
+ if (production._lhs == head and possibleMod == mod):
968
+ return True
969
+ return False
970
+
971
+ def __contains__(self, head, mod):
972
+ """
973
+ Return True if this ``DependencyGrammar`` contains a
974
+ ``DependencyProduction`` mapping 'head' to 'mod'.
975
+
976
+ :param head: A head word.
977
+ :type head: str
978
+ :param mod: A mod word, to test as a modifier of 'head'.
979
+ :type mod: str
980
+ :rtype: bool
981
+ """
982
+ for production in self._productions:
983
+ for possibleMod in production._rhs:
984
+ if (production._lhs == head and possibleMod == mod):
985
+ return True
986
+ return False
987
+
988
+ # # should be rewritten, the set comp won't work in all comparisons
989
+ # def contains_exactly(self, head, modlist):
990
+ # for production in self._productions:
991
+ # if(len(production._rhs) == len(modlist)):
992
+ # if(production._lhs == head):
993
+ # set1 = Set(production._rhs)
994
+ # set2 = Set(modlist)
995
+ # if(set1 == set2):
996
+ # return True
997
+ # return False
998
+
999
+ def __str__(self):
1000
+ """
1001
+ Return a verbose string representation of the ``DependencyGrammar``
1002
+
1003
+ :rtype: str
1004
+ """
1005
+ str = 'Dependency grammar with %d productions' % len(self._productions)
1006
+ for production in self._productions:
1007
+ str += '\n %s' % production
1008
+ return str
1009
+
1010
+ def __repr__(self):
1011
+ """
1012
+ Return a concise string representation of the ``DependencyGrammar``
1013
+ """
1014
+ return 'Dependency grammar with %d productions' % len(self._productions)
1015
+
1016
+
1017
+ @python_2_unicode_compatible
1018
+ class ProbabilisticDependencyGrammar(object):
1019
+ """
1020
+
1021
+ """
1022
+
1023
+ def __init__(self, productions, events, tags):
1024
+ self._productions = productions
1025
+ self._events = events
1026
+ self._tags = tags
1027
+
1028
+ def contains(self, head, mod):
1029
+ """
1030
+ Return True if this ``DependencyGrammar`` contains a
1031
+ ``DependencyProduction`` mapping 'head' to 'mod'.
1032
+
1033
+ :param head: A head word.
1034
+ :type head: str
1035
+ :param mod: A mod word, to test as a modifier of 'head'.
1036
+ :type mod: str
1037
+ :rtype: bool
1038
+ """
1039
+ for production in self._productions:
1040
+ for possibleMod in production._rhs:
1041
+ if (production._lhs == head and possibleMod == mod):
1042
+ return True
1043
+ return False
1044
+
1045
+ def __str__(self):
1046
+ """
1047
+ Return a verbose string representation of the ``ProbabilisticDependencyGrammar``
1048
+
1049
+ :rtype: str
1050
+ """
1051
+ str = 'Statistical dependency grammar with %d productions' % len(self._productions)
1052
+ for production in self._productions:
1053
+ str += '\n %s' % production
1054
+ str += '\nEvents:'
1055
+ for event in self._events:
1056
+ str += '\n %d:%s' % (self._events[event], event)
1057
+ str += '\nTags:'
1058
+ for tag_word in self._tags:
1059
+ str += '\n %s:\t(%s)' % (tag_word, self._tags[tag_word])
1060
+ return str
1061
+
1062
+ def __repr__(self):
1063
+ """
1064
+ Return a concise string representation of the ``ProbabilisticDependencyGrammar``
1065
+ """
1066
+ return 'Statistical Dependency grammar with %d productions' % len(self._productions)
1067
+
1068
+
1069
+ class PCFG(CFG):
1070
+ """
1071
+ A probabilistic context-free grammar. A PCFG consists of a
1072
+ start state and a set of productions with probabilities. The set of
1073
+ terminals and nonterminals is implicitly specified by the productions.
1074
+
1075
+ PCFG productions use the ``ProbabilisticProduction`` class.
1076
+ ``PCFGs`` impose the constraint that the set of productions with
1077
+ any given left-hand-side must have probabilities that sum to 1
1078
+ (allowing for a small margin of error).
1079
+
1080
+ If you need efficient key-based access to productions, you can use
1081
+ a subclass to implement it.
1082
+
1083
+ :type EPSILON: float
1084
+ :cvar EPSILON: The acceptable margin of error for checking that
1085
+ productions with a given left-hand side have probabilities
1086
+ that sum to 1.
1087
+ """
1088
+ EPSILON = 0.01
1089
+
1090
+ def __init__(self, start, productions, calculate_leftcorners=True):
1091
+ """
1092
+ Create a new context-free grammar, from the given start state
1093
+ and set of ``ProbabilisticProductions``.
1094
+
1095
+ :param start: The start symbol
1096
+ :type start: Nonterminal
1097
+ :param productions: The list of productions that defines the grammar
1098
+ :type productions: list(Production)
1099
+ :raise ValueError: if the set of productions with any left-hand-side
1100
+ do not have probabilities that sum to a value within
1101
+ EPSILON of 1.
1102
+ :param calculate_leftcorners: False if we don't want to calculate the
1103
+ leftcorner relation. In that case, some optimized chart parsers won't work.
1104
+ :type calculate_leftcorners: bool
1105
+ """
1106
+ CFG.__init__(self, start, productions, calculate_leftcorners)
1107
+
1108
+ # Make sure that the probabilities sum to one.
1109
+ probs = {}
1110
+ for production in productions:
1111
+ probs[production.lhs()] = (probs.get(production.lhs(), 0) +
1112
+ production.prob())
1113
+ for (lhs, p) in probs.items():
1114
+ if not ((1 - PCFG.EPSILON) < p <
1115
+ (1 + PCFG.EPSILON)):
1116
+ raise ValueError("Productions for %r do not sum to 1" % lhs)
1117
+
1118
+ @classmethod
1119
+ def fromstring(cls, input, encoding=None):
1120
+ """
1121
+ Return a probabilistic context-free grammar corresponding to the
1122
+ input string(s).
1123
+
1124
+ :param input: a grammar, either in the form of a string or else
1125
+ as a list of strings.
1126
+ """
1127
+ start, productions = read_grammar(input, standard_nonterm_parser,
1128
+ probabilistic=True, encoding=encoding)
1129
+ return cls(start, productions)
1130
+
1131
+
1132
+ #################################################################
1133
+ # Inducing Grammars
1134
+ #################################################################
1135
+
1136
+ # Contributed by Nathan Bodenstab <bodenstab@cslu.ogi.edu>
1137
+
1138
+ def induce_pcfg(start, productions):
1139
+ """
1140
+ Induce a PCFG grammar from a list of productions.
1141
+
1142
+ The probability of a production A -> B C in a PCFG is:
1143
+
1144
+ | count(A -> B C)
1145
+ | P(B, C | A) = --------------- where \* is any right hand side
1146
+ | count(A -> \*)
1147
+
1148
+ :param start: The start symbol
1149
+ :type start: Nonterminal
1150
+ :param productions: The list of productions that defines the grammar
1151
+ :type productions: list(Production)
1152
+ """
1153
+ # Production count: the number of times a given production occurs
1154
+ pcount = {}
1155
+
1156
+ # LHS-count: counts the number of times a given lhs occurs
1157
+ lcount = {}
1158
+
1159
+ for prod in productions:
1160
+ lcount[prod.lhs()] = lcount.get(prod.lhs(), 0) + 1
1161
+ pcount[prod] = pcount.get(prod, 0) + 1
1162
+
1163
+ prods = [ProbabilisticProduction(p.lhs(), p.rhs(),
1164
+ prob=pcount[p] / lcount[p.lhs()])
1165
+ for p in pcount]
1166
+ return PCFG(start, prods)
1167
+
1168
+
1169
+ #################################################################
1170
+ # Helper functions for reading productions
1171
+ #################################################################
1172
+
1173
+ def _read_cfg_production(input):
1174
+ """
1175
+ Return a list of context-free ``Productions``.
1176
+ """
1177
+ return _read_production(input, standard_nonterm_parser)
1178
+
1179
+
1180
+ def _read_pcfg_production(input):
1181
+ """
1182
+ Return a list of PCFG ``ProbabilisticProductions``.
1183
+ """
1184
+ return _read_production(input, standard_nonterm_parser, probabilistic=True)
1185
+
1186
+
1187
+ def _read_fcfg_production(input, fstruct_reader):
1188
+ """
1189
+ Return a list of feature-based ``Productions``.
1190
+ """
1191
+ return _read_production(input, fstruct_reader)
1192
+
1193
+
1194
+ # Parsing generic grammars
1195
+
1196
+ _ARROW_RE = re.compile(r'\s* -> \s*', re.VERBOSE)
1197
+ _PROBABILITY_RE = re.compile(r'( \[ [\d\.]+ \] ) \s*', re.VERBOSE)
1198
+ _TERMINAL_RE = re.compile(r'( "[^"]+" | \'[^\']+\' ) \s*', re.VERBOSE)
1199
+ _DISJUNCTION_RE = re.compile(r'\| \s*', re.VERBOSE)
1200
+
1201
+
1202
+ def _read_production(line, nonterm_parser, probabilistic=False):
1203
+ """
1204
+ Parse a grammar rule, given as a string, and return
1205
+ a list of productions.
1206
+ """
1207
+ pos = 0
1208
+
1209
+ # Parse the left-hand side.
1210
+ lhs, pos = nonterm_parser(line, pos)
1211
+
1212
+ # Skip over the arrow.
1213
+ m = _ARROW_RE.match(line, pos)
1214
+ if not m: raise ValueError('Expected an arrow')
1215
+ pos = m.end()
1216
+
1217
+ # Parse the right hand side.
1218
+ probabilities = [0.0]
1219
+ rhsides = [[]]
1220
+ while pos < len(line):
1221
+ # Probability.
1222
+ m = _PROBABILITY_RE.match(line, pos)
1223
+ if probabilistic and m:
1224
+ pos = m.end()
1225
+ probabilities[-1] = float(m.group(1)[1:-1])
1226
+ if probabilities[-1] > 1.0:
1227
+ raise ValueError('Production probability %f, '
1228
+ 'should not be greater than 1.0' %
1229
+ (probabilities[-1],))
1230
+
1231
+ # String -- add terminal.
1232
+ elif line[pos] in "\'\"":
1233
+ m = _TERMINAL_RE.match(line, pos)
1234
+ if not m: raise ValueError('Unterminated string')
1235
+ rhsides[-1].append(m.group(1)[1:-1])
1236
+ pos = m.end()
1237
+
1238
+ # Vertical bar -- start new rhside.
1239
+ elif line[pos] == '|':
1240
+ m = _DISJUNCTION_RE.match(line, pos)
1241
+ probabilities.append(0.0)
1242
+ rhsides.append([])
1243
+ pos = m.end()
1244
+
1245
+ # Anything else -- nonterminal.
1246
+ else:
1247
+ nonterm, pos = nonterm_parser(line, pos)
1248
+ rhsides[-1].append(nonterm)
1249
+
1250
+ if probabilistic:
1251
+ return [ProbabilisticProduction(lhs, rhs, prob=probability)
1252
+ for (rhs, probability) in zip(rhsides, probabilities)]
1253
+ else:
1254
+ return [Production(lhs, rhs) for rhs in rhsides]
1255
+
1256
+
1257
+ #################################################################
1258
+ # Reading Phrase Structure Grammars
1259
+ #################################################################
1260
+
1261
+ def read_grammar(input, nonterm_parser, probabilistic=False, encoding=None):
1262
+ """
1263
+ Return a pair consisting of a starting category and a list of
1264
+ ``Productions``.
1265
+
1266
+ :param input: a grammar, either in the form of a string or else
1267
+ as a list of strings.
1268
+ :param nonterm_parser: a function for parsing nonterminals.
1269
+ It should take a ``(string, position)`` as argument and
1270
+ return a ``(nonterminal, position)`` as result.
1271
+ :param probabilistic: are the grammar rules probabilistic?
1272
+ :type probabilistic: bool
1273
+ :param encoding: the encoding of the grammar, if it is a binary string
1274
+ :type encoding: str
1275
+ """
1276
+ if encoding is not None:
1277
+ input = input.decode(encoding)
1278
+ if isinstance(input, string_types):
1279
+ lines = input.split('\n')
1280
+ else:
1281
+ lines = input
1282
+
1283
+ start = None
1284
+ productions = []
1285
+ continue_line = ''
1286
+ for linenum, line in enumerate(lines):
1287
+ line = continue_line + line.strip()
1288
+ if line.startswith('#') or line == '': continue
1289
+ if line.endswith('\\'):
1290
+ continue_line = line[:-1].rstrip() + ' '
1291
+ continue
1292
+ continue_line = ''
1293
+ try:
1294
+ if line[0] == '%':
1295
+ directive, args = line[1:].split(None, 1)
1296
+ if directive == 'start':
1297
+ start, pos = nonterm_parser(args, 0)
1298
+ if pos != len(args):
1299
+ raise ValueError('Bad argument to start directive')
1300
+ else:
1301
+ raise ValueError('Bad directive')
1302
+ else:
1303
+ # expand out the disjunctions on the RHS
1304
+ productions += _read_production(line, nonterm_parser, probabilistic)
1305
+ except ValueError as e:
1306
+ raise ValueError('Unable to parse line %s: %s\n%s' %
1307
+ (linenum + 1, line, e))
1308
+
1309
+ if not productions:
1310
+ raise ValueError('No productions found!')
1311
+ if not start:
1312
+ start = productions[0].lhs()
1313
+ return (start, productions)
1314
+
1315
+
1316
+ _STANDARD_NONTERM_RE = re.compile('( [\w/][\w/^<>-]* ) \s*', re.VERBOSE)
1317
+
1318
+
1319
+ def standard_nonterm_parser(string, pos):
1320
+ m = _STANDARD_NONTERM_RE.match(string, pos)
1321
+ if not m: raise ValueError('Expected a nonterminal, found: '
1322
+ + string[pos:])
1323
+ return (Nonterminal(m.group(1)), m.end())
1324
+
1325
+
1326
+ #################################################################
1327
+ # Reading Dependency Grammars
1328
+ #################################################################
1329
+
1330
+ _READ_DG_RE = re.compile(r'''^\s* # leading whitespace
1331
+ ('[^']+')\s* # single-quoted lhs
1332
+ (?:[-=]+>)\s* # arrow
1333
+ (?:( # rhs:
1334
+ "[^"]+" # doubled-quoted terminal
1335
+ | '[^']+' # single-quoted terminal
1336
+ | \| # disjunction
1337
+ )
1338
+ \s*) # trailing space
1339
+ *$''', # zero or more copies
1340
+ re.VERBOSE)
1341
+ _SPLIT_DG_RE = re.compile(r'''('[^']'|[-=]+>|"[^"]+"|'[^']+'|\|)''')
1342
+
1343
+
1344
+ def _read_dependency_production(s):
1345
+ if not _READ_DG_RE.match(s):
1346
+ raise ValueError('Bad production string')
1347
+ pieces = _SPLIT_DG_RE.split(s)
1348
+ pieces = [p for i, p in enumerate(pieces) if i % 2 == 1]
1349
+ lhside = pieces[0].strip('\'\"')
1350
+ rhsides = [[]]
1351
+ for piece in pieces[2:]:
1352
+ if piece == '|':
1353
+ rhsides.append([])
1354
+ else:
1355
+ rhsides[-1].append(piece.strip('\'\"'))
1356
+ return [DependencyProduction(lhside, rhside) for rhside in rhsides]
1357
+
1358
+
1359
+ #################################################################
1360
+ # Demonstration
1361
+ #################################################################
1362
+
1363
+ def cfg_demo():
1364
+ """
1365
+ A demonstration showing how ``CFGs`` can be created and used.
1366
+ """
1367
+
1368
+ from nltk import nonterminals, Production, CFG
1369
+
1370
+ # Create some nonterminals
1371
+ S, NP, VP, PP = nonterminals('S, NP, VP, PP')
1372
+ N, V, P, Det = nonterminals('N, V, P, Det')
1373
+ VP_slash_NP = VP / NP
1374
+
1375
+ print('Some nonterminals:', [S, NP, VP, PP, N, V, P, Det, VP / NP])
1376
+ print(' S.symbol() =>', repr(S.symbol()))
1377
+ print()
1378
+
1379
+ print(Production(S, [NP]))
1380
+
1381
+ # Create some Grammar Productions
1382
+ grammar = CFG.fromstring("""
1383
+ S -> NP VP
1384
+ PP -> P NP
1385
+ NP -> Det N | NP PP
1386
+ VP -> V NP | VP PP
1387
+ Det -> 'a' | 'the'
1388
+ N -> 'dog' | 'cat'
1389
+ V -> 'chased' | 'sat'
1390
+ P -> 'on' | 'in'
1391
+ """)
1392
+
1393
+ print('A Grammar:', repr(grammar))
1394
+ print(' grammar.start() =>', repr(grammar.start()))
1395
+ print(' grammar.productions() =>', end=' ')
1396
+ # Use string.replace(...) is to line-wrap the output.
1397
+ print(repr(grammar.productions()).replace(',', ',\n' + ' ' * 25))
1398
+ print()
1399
+
1400
+
1401
+ toy_pcfg1 = PCFG.fromstring("""
1402
+ S -> NP VP [1.0]
1403
+ NP -> Det N [0.5] | NP PP [0.25] | 'John' [0.1] | 'I' [0.15]
1404
+ Det -> 'the' [0.8] | 'my' [0.2]
1405
+ N -> 'man' [0.5] | 'telescope' [0.5]
1406
+ VP -> VP PP [0.1] | V NP [0.7] | V [0.2]
1407
+ V -> 'ate' [0.35] | 'saw' [0.65]
1408
+ PP -> P NP [1.0]
1409
+ P -> 'with' [0.61] | 'under' [0.39]
1410
+ """)
1411
+
1412
+ toy_pcfg2 = PCFG.fromstring("""
1413
+ S -> NP VP [1.0]
1414
+ VP -> V NP [.59]
1415
+ VP -> V [.40]
1416
+ VP -> VP PP [.01]
1417
+ NP -> Det N [.41]
1418
+ NP -> Name [.28]
1419
+ NP -> NP PP [.31]
1420
+ PP -> P NP [1.0]
1421
+ V -> 'saw' [.21]
1422
+ V -> 'ate' [.51]
1423
+ V -> 'ran' [.28]
1424
+ N -> 'boy' [.11]
1425
+ N -> 'cookie' [.12]
1426
+ N -> 'table' [.13]
1427
+ N -> 'telescope' [.14]
1428
+ N -> 'hill' [.5]
1429
+ Name -> 'Jack' [.52]
1430
+ Name -> 'Bob' [.48]
1431
+ P -> 'with' [.61]
1432
+ P -> 'under' [.39]
1433
+ Det -> 'the' [.41]
1434
+ Det -> 'a' [.31]
1435
+ Det -> 'my' [.28]
1436
+ """)
1437
+
1438
+
1439
+ def pcfg_demo():
1440
+ """
1441
+ A demonstration showing how a ``PCFG`` can be created and used.
1442
+ """
1443
+
1444
+ from nltk.corpus import treebank
1445
+ from nltk import treetransforms
1446
+ from nltk import induce_pcfg
1447
+ from nltk.parse import pchart
1448
+
1449
+ pcfg_prods = toy_pcfg1.productions()
1450
+
1451
+ pcfg_prod = pcfg_prods[2]
1452
+ print('A PCFG production:', repr(pcfg_prod))
1453
+ print(' pcfg_prod.lhs() =>', repr(pcfg_prod.lhs()))
1454
+ print(' pcfg_prod.rhs() =>', repr(pcfg_prod.rhs()))
1455
+ print(' pcfg_prod.prob() =>', repr(pcfg_prod.prob()))
1456
+ print()
1457
+
1458
+ grammar = toy_pcfg2
1459
+ print('A PCFG grammar:', repr(grammar))
1460
+ print(' grammar.start() =>', repr(grammar.start()))
1461
+ print(' grammar.productions() =>', end=' ')
1462
+ # Use .replace(...) is to line-wrap the output.
1463
+ print(repr(grammar.productions()).replace(',', ',\n' + ' ' * 26))
1464
+ print()
1465
+
1466
+ # extract productions from three trees and induce the PCFG
1467
+ print("Induce PCFG grammar from treebank data:")
1468
+
1469
+ productions = []
1470
+ item = treebank._fileids[0]
1471
+ for tree in treebank.parsed_sents(item)[:3]:
1472
+ # perform optional tree transformations, e.g.:
1473
+ tree.collapse_unary(collapsePOS=False)
1474
+ tree.chomsky_normal_form(horzMarkov=2)
1475
+
1476
+ productions += tree.productions()
1477
+
1478
+ S = Nonterminal('S')
1479
+ grammar = induce_pcfg(S, productions)
1480
+ print(grammar)
1481
+ print()
1482
+
1483
+ print("Parse sentence using induced grammar:")
1484
+
1485
+ parser = pchart.InsideChartParser(grammar)
1486
+ parser.trace(3)
1487
+
1488
+ # doesn't work as tokens are different:
1489
+ # sent = treebank.tokenized('wsj_0001.mrg')[0]
1490
+
1491
+ sent = treebank.parsed_sents(item)[0].leaves()
1492
+ print(sent)
1493
+ for parse in parser.parse(sent):
1494
+ print(parse)
1495
+
1496
+
1497
+ def fcfg_demo():
1498
+ import nltk.data
1499
+ g = nltk.data.load('grammars/book_grammars/feat0.fcfg')
1500
+ print(g)
1501
+ print()
1502
+
1503
+
1504
+ def dg_demo():
1505
+ """
1506
+ A demonstration showing the creation and inspection of a
1507
+ ``DependencyGrammar``.
1508
+ """
1509
+ grammar = DependencyGrammar.fromstring("""
1510
+ 'scratch' -> 'cats' | 'walls'
1511
+ 'walls' -> 'the'
1512
+ 'cats' -> 'the'
1513
+ """)
1514
+ print(grammar)
1515
+
1516
+
1517
+ def sdg_demo():
1518
+ """
1519
+ A demonstration of how to read a string representation of
1520
+ a CoNLL format dependency tree.
1521
+ """
1522
+ from nltk.parse import DependencyGraph
1523
+
1524
+ dg = DependencyGraph("""
1525
+ 1 Ze ze Pron Pron per|3|evofmv|nom 2 su _ _
1526
+ 2 had heb V V trans|ovt|1of2of3|ev 0 ROOT _ _
1527
+ 3 met met Prep Prep voor 8 mod _ _
1528
+ 4 haar haar Pron Pron bez|3|ev|neut|attr 5 det _ _
1529
+ 5 moeder moeder N N soort|ev|neut 3 obj1 _ _
1530
+ 6 kunnen kan V V hulp|ott|1of2of3|mv 2 vc _ _
1531
+ 7 gaan ga V V hulp|inf 6 vc _ _
1532
+ 8 winkelen winkel V V intrans|inf 11 cnj _ _
1533
+ 9 , , Punc Punc komma 8 punct _ _
1534
+ 10 zwemmen zwem V V intrans|inf 11 cnj _ _
1535
+ 11 of of Conj Conj neven 7 vc _ _
1536
+ 12 terrassen terras N N soort|mv|neut 11 cnj _ _
1537
+ 13 . . Punc Punc punt 12 punct _ _
1538
+ """)
1539
+ tree = dg.tree()
1540
+ print(tree.pprint())
1541
+
1542
+
1543
+ def demo():
1544
+ cfg_demo()
1545
+ pcfg_demo()
1546
+ fcfg_demo()
1547
+ dg_demo()
1548
+ sdg_demo()
1549
+
1550
+
1551
+ if __name__ == '__main__':
1552
+ demo()
1553
+
1554
+ __all__ = ['Nonterminal', 'nonterminals',
1555
+ 'CFG', 'Production',
1556
+ 'PCFG', 'ProbabilisticProduction',
1557
+ 'DependencyGrammar', 'DependencyProduction',
1558
+ 'ProbabilisticDependencyGrammar',
1559
+ 'induce_pcfg', 'read_grammar']