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.
- {nltk-3.2 → nltk-3.3}/INSTALL.txt +6 -6
- {nltk-3.2 → nltk-3.3}/LICENSE.txt +13 -13
- {nltk-3.2 → nltk-3.3}/MANIFEST.in +6 -6
- {nltk-3.2/nltk.egg-info → nltk-3.3}/PKG-INFO +13 -5
- nltk-3.2/README.txt → nltk-3.3/README.md +49 -48
- nltk-3.3/nltk/VERSION +1 -0
- {nltk-3.2 → nltk-3.3}/nltk/__init__.py +185 -185
- {nltk-3.2 → nltk-3.3}/nltk/app/__init__.py +52 -53
- {nltk-3.2 → nltk-3.3}/nltk/app/chartparser_app.py +2276 -2276
- {nltk-3.2 → nltk-3.3}/nltk/app/chunkparser_app.py +1262 -1264
- {nltk-3.2 → nltk-3.3}/nltk/app/collocations_app.py +347 -350
- {nltk-3.2 → nltk-3.3}/nltk/app/concordance_app.py +568 -570
- {nltk-3.2 → nltk-3.3}/nltk/app/nemo_app.py +156 -155
- {nltk-3.2 → nltk-3.3}/nltk/app/rdparser_app.py +892 -894
- {nltk-3.2 → nltk-3.3}/nltk/app/srparser_app.py +809 -809
- {nltk-3.2 → nltk-3.3}/nltk/app/wordfreq_app.py +32 -32
- {nltk-3.2 → nltk-3.3}/nltk/app/wordnet_app.py +968 -968
- {nltk-3.2 → nltk-3.3}/nltk/book.py +91 -90
- {nltk-3.2 → nltk-3.3}/nltk/ccg/__init__.py +22 -22
- {nltk-3.2 → nltk-3.3}/nltk/ccg/api.py +359 -335
- {nltk-3.2 → nltk-3.3}/nltk/ccg/chart.py +394 -361
- {nltk-3.2 → nltk-3.3}/nltk/ccg/combinator.py +343 -312
- {nltk-3.2 → nltk-3.3}/nltk/ccg/lexicon.py +328 -290
- nltk-3.3/nltk/ccg/logic.py +46 -0
- {nltk-3.2 → nltk-3.3}/nltk/chat/__init__.py +49 -49
- {nltk-3.2 → nltk-3.3}/nltk/chat/eliza.py +244 -244
- {nltk-3.2 → nltk-3.3}/nltk/chat/iesha.py +140 -140
- {nltk-3.2 → nltk-3.3}/nltk/chat/rude.py +92 -92
- {nltk-3.2 → nltk-3.3}/nltk/chat/suntsu.py +117 -117
- {nltk-3.2 → nltk-3.3}/nltk/chat/util.py +122 -120
- {nltk-3.2 → nltk-3.3}/nltk/chat/zen.py +282 -282
- {nltk-3.2 → nltk-3.3}/nltk/chunk/__init__.py +190 -190
- {nltk-3.2 → nltk-3.3}/nltk/chunk/api.py +51 -51
- {nltk-3.2 → nltk-3.3}/nltk/chunk/named_entity.py +331 -331
- {nltk-3.2 → nltk-3.3}/nltk/chunk/regexp.py +1390 -1384
- {nltk-3.2 → nltk-3.3}/nltk/chunk/util.py +600 -600
- {nltk-3.2 → nltk-3.3}/nltk/classify/__init__.py +98 -98
- {nltk-3.2 → nltk-3.3}/nltk/classify/api.py +193 -193
- {nltk-3.2 → nltk-3.3}/nltk/classify/decisiontree.py +295 -295
- {nltk-3.2 → nltk-3.3}/nltk/classify/maxent.py +1510 -1492
- {nltk-3.2 → nltk-3.3}/nltk/classify/megam.py +179 -178
- {nltk-3.2 → nltk-3.3}/nltk/classify/naivebayes.py +245 -242
- {nltk-3.2 → nltk-3.3}/nltk/classify/positivenaivebayes.py +170 -170
- {nltk-3.2 → nltk-3.3}/nltk/classify/rte_classify.py +160 -191
- {nltk-3.2 → nltk-3.3}/nltk/classify/scikitlearn.py +153 -151
- {nltk-3.2 → nltk-3.3}/nltk/classify/senna.py +183 -181
- {nltk-3.2 → nltk-3.3}/nltk/classify/svm.py +15 -15
- {nltk-3.2 → nltk-3.3}/nltk/classify/tadm.py +113 -112
- {nltk-3.2 → nltk-3.3}/nltk/classify/textcat.py +193 -193
- {nltk-3.2 → nltk-3.3}/nltk/classify/util.py +324 -312
- {nltk-3.2 → nltk-3.3}/nltk/classify/weka.py +346 -345
- {nltk-3.2 → nltk-3.3}/nltk/cluster/__init__.py +86 -86
- {nltk-3.2 → nltk-3.3}/nltk/cluster/api.py +74 -70
- {nltk-3.2 → nltk-3.3}/nltk/cluster/em.py +247 -247
- {nltk-3.2 → nltk-3.3}/nltk/cluster/gaac.py +168 -168
- {nltk-3.2 → nltk-3.3}/nltk/cluster/kmeans.py +221 -221
- {nltk-3.2 → nltk-3.3}/nltk/cluster/util.py +304 -289
- nltk-3.3/nltk/collections.py +640 -0
- {nltk-3.2 → nltk-3.3}/nltk/collocations.py +388 -388
- nltk-3.3/nltk/compat.py +365 -0
- {nltk-3.2 → nltk-3.3}/nltk/corpus/__init__.py +341 -320
- {nltk-3.2 → nltk-3.3}/nltk/corpus/europarl_raw.py +44 -44
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/__init__.py +147 -145
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/aligned.py +115 -114
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/api.py +448 -446
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/bnc.py +252 -252
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/bracket_parse.py +227 -227
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/categorized_sents.py +179 -178
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/chasen.py +140 -139
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/childes.py +522 -494
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/chunked.py +212 -212
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/cmudict.py +97 -95
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/comparative_sents.py +280 -278
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/conll.py +528 -521
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/crubadan.py +116 -116
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/dependency.py +101 -101
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/framenet.py +3059 -2093
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ieer.py +112 -111
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/indian.py +85 -86
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ipipan.py +332 -331
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/knbc.py +187 -187
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/lin.py +156 -156
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/mte.py +311 -310
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nkjp.py +429 -428
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nombank.py +421 -421
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nps_chat.py +73 -73
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/opinion_lexicon.py +115 -115
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/panlex_lite.py +165 -165
- nltk-3.3/nltk/corpus/reader/pl196x.py +292 -0
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/plaintext.py +232 -233
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ppattach.py +96 -95
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/propbank.py +479 -481
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/pros_cons.py +128 -126
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/reviews.py +330 -328
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/rte.py +144 -146
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/semcor.py +256 -256
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/senseval.py +203 -201
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/sentiwordnet.py +137 -137
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/sinica_treebank.py +75 -75
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/string_category.py +60 -59
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/switchboard.py +119 -119
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/tagged.py +295 -294
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/timit.py +452 -450
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/toolbox.py +68 -68
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/twitter.py +155 -157
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/udhr.py +80 -80
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/util.py +804 -800
- nltk-3.3/nltk/corpus/reader/verbnet.py +595 -0
- nltk-3.3/nltk/corpus/reader/wordlist.py +134 -0
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/wordnet.py +2108 -2036
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/xmldocs.py +392 -387
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ycoe.py +243 -242
- {nltk-3.2 → nltk-3.3}/nltk/corpus/util.py +144 -127
- {nltk-3.2 → nltk-3.3}/nltk/data.py +1487 -1451
- {nltk-3.2 → nltk-3.3}/nltk/decorators.py +219 -215
- {nltk-3.2 → nltk-3.3}/nltk/downloader.py +2278 -2274
- {nltk-3.2 → nltk-3.3}/nltk/draw/__init__.py +27 -27
- {nltk-3.2 → nltk-3.3}/nltk/draw/cfg.py +774 -777
- {nltk-3.2 → nltk-3.3}/nltk/draw/dispersion.py +58 -58
- {nltk-3.2 → nltk-3.3}/nltk/draw/table.py +1098 -1098
- {nltk-3.2 → nltk-3.3}/nltk/draw/tree.py +963 -966
- {nltk-3.2 → nltk-3.3}/nltk/draw/util.py +2356 -2356
- {nltk-3.2 → nltk-3.3}/nltk/featstruct.py +2617 -2500
- {nltk-3.2 → nltk-3.3}/nltk/grammar.py +1559 -1516
- {nltk-3.2 → nltk-3.3}/nltk/help.py +56 -56
- {nltk-3.2 → nltk-3.3}/nltk/inference/__init__.py +20 -20
- {nltk-3.2 → nltk-3.3}/nltk/inference/api.py +597 -589
- {nltk-3.2 → nltk-3.3}/nltk/inference/discourse.py +612 -608
- {nltk-3.2 → nltk-3.3}/nltk/inference/mace.py +311 -311
- {nltk-3.2 → nltk-3.3}/nltk/inference/nonmonotonic.py +509 -509
- {nltk-3.2 → nltk-3.3}/nltk/inference/prover9.py +431 -431
- {nltk-3.2 → nltk-3.3}/nltk/inference/resolution.py +687 -687
- {nltk-3.2 → nltk-3.3}/nltk/inference/tableau.py +607 -607
- {nltk-3.2 → nltk-3.3}/nltk/internals.py +982 -982
- {nltk-3.2 → nltk-3.3}/nltk/jsontags.py +63 -63
- {nltk-3.2 → nltk-3.3}/nltk/lazyimport.py +142 -142
- {nltk-3.2 → nltk-3.3}/nltk/metrics/__init__.py +30 -29
- {nltk-3.2 → nltk-3.3}/nltk/metrics/agreement.py +421 -401
- nltk-3.3/nltk/metrics/aline.py +607 -0
- {nltk-3.2 → nltk-3.3}/nltk/metrics/association.py +414 -410
- {nltk-3.2 → nltk-3.3}/nltk/metrics/confusionmatrix.py +206 -206
- {nltk-3.2 → nltk-3.3}/nltk/metrics/distance.py +207 -202
- {nltk-3.2 → nltk-3.3}/nltk/metrics/paice.py +381 -381
- {nltk-3.2 → nltk-3.3}/nltk/metrics/scores.py +228 -228
- {nltk-3.2 → nltk-3.3}/nltk/metrics/segmentation.py +231 -232
- {nltk-3.2 → nltk-3.3}/nltk/metrics/spearman.py +69 -69
- {nltk-3.2 → nltk-3.3}/nltk/misc/__init__.py +11 -11
- {nltk-3.2 → nltk-3.3}/nltk/misc/babelfish.py +10 -10
- {nltk-3.2 → nltk-3.3}/nltk/misc/chomsky.py +135 -133
- {nltk-3.2 → nltk-3.3}/nltk/misc/minimalset.py +83 -83
- {nltk-3.2 → nltk-3.3}/nltk/misc/sort.py +157 -157
- {nltk-3.2 → nltk-3.3}/nltk/misc/wordfinder.py +129 -129
- {nltk-3.2 → nltk-3.3}/nltk/parse/__init__.py +81 -80
- {nltk-3.2 → nltk-3.3}/nltk/parse/api.py +66 -66
- {nltk-3.2 → nltk-3.3}/nltk/parse/bllip.py +282 -282
- {nltk-3.2 → nltk-3.3}/nltk/parse/chart.py +1682 -1681
- nltk-3.3/nltk/parse/corenlp.py +780 -0
- {nltk-3.2 → nltk-3.3}/nltk/parse/dependencygraph.py +760 -758
- {nltk-3.2 → nltk-3.3}/nltk/parse/earleychart.py +452 -451
- {nltk-3.2 → nltk-3.3}/nltk/parse/evaluate.py +129 -129
- {nltk-3.2 → nltk-3.3}/nltk/parse/featurechart.py +580 -578
- {nltk-3.2 → nltk-3.3}/nltk/parse/generate.py +87 -76
- {nltk-3.2 → nltk-3.3}/nltk/parse/malt.py +356 -356
- {nltk-3.2 → nltk-3.3}/nltk/parse/nonprojectivedependencyparser.py +783 -783
- {nltk-3.2 → nltk-3.3}/nltk/parse/pchart.py +522 -522
- {nltk-3.2 → nltk-3.3}/nltk/parse/projectivedependencyparser.py +579 -578
- {nltk-3.2 → nltk-3.3}/nltk/parse/recursivedescent.py +655 -656
- {nltk-3.2 → nltk-3.3}/nltk/parse/shiftreduce.py +458 -459
- {nltk-3.2 → nltk-3.3}/nltk/parse/stanford.py +431 -406
- {nltk-3.2 → nltk-3.3}/nltk/parse/transitionparser.py +774 -772
- {nltk-3.2 → nltk-3.3}/nltk/parse/util.py +231 -231
- {nltk-3.2 → nltk-3.3}/nltk/parse/viterbi.py +401 -401
- {nltk-3.2 → nltk-3.3}/nltk/probability.py +2410 -2355
- {nltk-3.2 → nltk-3.3}/nltk/sem/__init__.py +61 -61
- {nltk-3.2 → nltk-3.3}/nltk/sem/boxer.py +1261 -1261
- {nltk-3.2 → nltk-3.3}/nltk/sem/chat80.py +782 -782
- {nltk-3.2 → nltk-3.3}/nltk/sem/cooper_storage.py +118 -118
- {nltk-3.2 → nltk-3.3}/nltk/sem/drt.py +1258 -1257
- {nltk-3.2 → nltk-3.3}/nltk/sem/drt_glue_demo.py +485 -489
- {nltk-3.2 → nltk-3.3}/nltk/sem/evaluate.py +790 -784
- {nltk-3.2 → nltk-3.3}/nltk/sem/glue.py +696 -694
- {nltk-3.2 → nltk-3.3}/nltk/sem/hole.py +386 -384
- {nltk-3.2 → nltk-3.3}/nltk/sem/lfg.py +210 -208
- {nltk-3.2 → nltk-3.3}/nltk/sem/linearlogic.py +451 -449
- {nltk-3.2 → nltk-3.3}/nltk/sem/logic.py +1910 -1910
- {nltk-3.2 → nltk-3.3}/nltk/sem/relextract.py +476 -483
- {nltk-3.2 → nltk-3.3}/nltk/sem/skolemize.py +101 -101
- {nltk-3.2 → nltk-3.3}/nltk/sem/util.py +249 -249
- {nltk-3.2 → nltk-3.3}/nltk/sentiment/__init__.py +14 -14
- {nltk-3.2 → nltk-3.3}/nltk/sentiment/sentiment_analyzer.py +229 -229
- {nltk-3.2 → nltk-3.3}/nltk/sentiment/util.py +762 -752
- {nltk-3.2 → nltk-3.3}/nltk/sentiment/vader.py +443 -445
- {nltk-3.2 → nltk-3.3}/nltk/stem/__init__.py +31 -33
- {nltk-3.2 → nltk-3.3}/nltk/stem/api.py +28 -25
- nltk-3.3/nltk/stem/arlstem.py +369 -0
- {nltk-3.2 → nltk-3.3}/nltk/stem/isri.py +345 -345
- {nltk-3.2 → nltk-3.3}/nltk/stem/lancaster.py +337 -310
- nltk-3.3/nltk/stem/porter.py +710 -0
- {nltk-3.2 → nltk-3.3}/nltk/stem/regexp.py +61 -61
- {nltk-3.2 → nltk-3.3}/nltk/stem/rslp.py +142 -142
- {nltk-3.2 → nltk-3.3}/nltk/stem/snowball.py +4236 -3712
- {nltk-3.2 → nltk-3.3}/nltk/stem/util.py +22 -12
- {nltk-3.2 → nltk-3.3}/nltk/stem/wordnet.py +51 -51
- {nltk-3.2 → nltk-3.3}/nltk/tag/__init__.py +152 -127
- {nltk-3.2 → nltk-3.3}/nltk/tag/api.py +86 -81
- {nltk-3.2 → nltk-3.3}/nltk/tag/brill.py +424 -426
- {nltk-3.2 → nltk-3.3}/nltk/tag/brill_trainer.py +608 -608
- {nltk-3.2 → nltk-3.3}/nltk/tag/crf.py +204 -200
- {nltk-3.2 → nltk-3.3}/nltk/tag/hmm.py +1277 -1277
- {nltk-3.2 → nltk-3.3}/nltk/tag/hunpos.py +132 -132
- {nltk-3.2 → nltk-3.3}/nltk/tag/mapping.py +101 -101
- {nltk-3.2 → nltk-3.3}/nltk/tag/perceptron.py +329 -314
- {nltk-3.2 → nltk-3.3}/nltk/tag/senna.py +147 -145
- {nltk-3.2 → nltk-3.3}/nltk/tag/sequential.py +740 -736
- {nltk-3.2 → nltk-3.3}/nltk/tag/stanford.py +219 -196
- {nltk-3.2 → nltk-3.3}/nltk/tag/tnt.py +595 -604
- {nltk-3.2 → nltk-3.3}/nltk/tag/util.py +72 -72
- {nltk-3.2 → nltk-3.3}/nltk/tbl/__init__.py +28 -28
- {nltk-3.2 → nltk-3.3}/nltk/tbl/api.py +1 -1
- {nltk-3.2 → nltk-3.3}/nltk/tbl/demo.py +366 -366
- {nltk-3.2 → nltk-3.3}/nltk/tbl/erroranalysis.py +39 -39
- {nltk-3.2 → nltk-3.3}/nltk/tbl/feature.py +259 -261
- {nltk-3.2 → nltk-3.3}/nltk/tbl/rule.py +321 -321
- {nltk-3.2 → nltk-3.3}/nltk/tbl/template.py +303 -308
- {nltk-3.2 → nltk-3.3}/nltk/test/__init__.py +18 -18
- {nltk-3.2 → nltk-3.3}/nltk/test/all.py +24 -23
- {nltk-3.2 → nltk-3.3}/nltk/test/bleu.doctest +14 -14
- {nltk-3.2 → nltk-3.3}/nltk/test/bnc.doctest +60 -60
- {nltk-3.2 → nltk-3.3}/nltk/test/ccg.doctest +376 -395
- nltk-3.3/nltk/test/ccg_semantics.doctest +553 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/chat80.doctest +234 -234
- {nltk-3.2 → nltk-3.3}/nltk/test/childes.doctest +184 -184
- {nltk-3.2 → nltk-3.3}/nltk/test/childes_fixt.py +14 -13
- {nltk-3.2 → nltk-3.3}/nltk/test/chunk.doctest +373 -373
- {nltk-3.2 → nltk-3.3}/nltk/test/classify.doctest +185 -185
- {nltk-3.2 → nltk-3.3}/nltk/test/classify_fixt.py +11 -10
- nltk-3.3/nltk/test/collections.doctest +20 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/collocations.doctest +276 -276
- {nltk-3.2 → nltk-3.3}/nltk/test/compat.doctest +134 -138
- {nltk-3.2 → nltk-3.3}/nltk/test/compat_fixt.py +9 -8
- nltk-3.3/nltk/test/concordance.doctest +55 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/corpus.doctest +2200 -2212
- {nltk-3.2 → nltk-3.3}/nltk/test/corpus_fixt.py +3 -3
- {nltk-3.2 → nltk-3.3}/nltk/test/crubadan.doctest +65 -65
- {nltk-3.2 → nltk-3.3}/nltk/test/data.doctest +379 -379
- {nltk-3.2 → nltk-3.3}/nltk/test/dependency.doctest +241 -241
- {nltk-3.2 → nltk-3.3}/nltk/test/discourse.doctest +546 -546
- {nltk-3.2 → nltk-3.3}/nltk/test/discourse_fixt.py +14 -13
- {nltk-3.2 → nltk-3.3}/nltk/test/doctest_nose_plugin.py +159 -156
- {nltk-3.2 → nltk-3.3}/nltk/test/drt.doctest +517 -517
- {nltk-3.2 → nltk-3.3}/nltk/test/featgram.doctest +607 -607
- {nltk-3.2 → nltk-3.3}/nltk/test/featstruct.doctest +1229 -1230
- {nltk-3.2 → nltk-3.3}/nltk/test/framenet.doctest +288 -239
- {nltk-3.2 → nltk-3.3}/nltk/test/generate.doctest +67 -67
- {nltk-3.2 → nltk-3.3}/nltk/test/gensim.doctest +140 -141
- {nltk-3.2 → nltk-3.3}/nltk/test/gensim_fixt.py +10 -9
- {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics.doctest +384 -386
- {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics_malt.doctest +68 -68
- {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics_malt_fixt.py +12 -11
- {nltk-3.2 → nltk-3.3}/nltk/test/grammar.doctest +48 -48
- {nltk-3.2 → nltk-3.3}/nltk/test/grammartestsuites.doctest +109 -109
- {nltk-3.2 → nltk-3.3}/nltk/test/index.doctest +100 -100
- {nltk-3.2 → nltk-3.3}/nltk/test/inference.doctest +534 -534
- {nltk-3.2 → nltk-3.3}/nltk/test/inference_fixt.py +12 -11
- {nltk-3.2 → nltk-3.3}/nltk/test/internals.doctest +140 -140
- {nltk-3.2 → nltk-3.3}/nltk/test/japanese.doctest +48 -48
- {nltk-3.2 → nltk-3.3}/nltk/test/logic.doctest +1098 -1098
- {nltk-3.2 → nltk-3.3}/nltk/test/metrics.doctest +270 -270
- {nltk-3.2 → nltk-3.3}/nltk/test/misc.doctest +118 -118
- {nltk-3.2 → nltk-3.3}/nltk/test/nonmonotonic.doctest +286 -286
- {nltk-3.2 → nltk-3.3}/nltk/test/nonmonotonic_fixt.py +12 -11
- {nltk-3.2 → nltk-3.3}/nltk/test/paice.doctest +35 -35
- {nltk-3.2 → nltk-3.3}/nltk/test/parse.doctest +884 -884
- {nltk-3.2 → nltk-3.3}/nltk/test/portuguese_en.doctest +565 -565
- {nltk-3.2 → nltk-3.3}/nltk/test/portuguese_en_fixt.py +16 -16
- {nltk-3.2 → nltk-3.3}/nltk/test/probability.doctest +304 -304
- {nltk-3.2 → nltk-3.3}/nltk/test/probability_fixt.py +13 -12
- {nltk-3.2 → nltk-3.3}/nltk/test/propbank.doctest +176 -176
- {nltk-3.2 → nltk-3.3}/nltk/test/relextract.doctest +263 -263
- {nltk-3.2 → nltk-3.3}/nltk/test/resolution.doctest +221 -221
- {nltk-3.2 → nltk-3.3}/nltk/test/runtests.py +86 -64
- {nltk-3.2 → nltk-3.3}/nltk/test/segmentation_fixt.py +10 -10
- {nltk-3.2 → nltk-3.3}/nltk/test/semantics.doctest +665 -665
- {nltk-3.2 → nltk-3.3}/nltk/test/semantics_fixt.py +7 -7
- {nltk-3.2 → nltk-3.3}/nltk/test/sentiment.doctest +233 -233
- {nltk-3.2 → nltk-3.3}/nltk/test/sentiwordnet.doctest +41 -41
- {nltk-3.2 → nltk-3.3}/nltk/test/simple.doctest +85 -85
- {nltk-3.2 → nltk-3.3}/nltk/test/stem.doctest +78 -78
- {nltk-3.2 → nltk-3.3}/nltk/test/tag.doctest +33 -33
- {nltk-3.2 → nltk-3.3}/nltk/test/tokenize.doctest +273 -166
- {nltk-3.2 → nltk-3.3}/nltk/test/toolbox.doctest +307 -307
- {nltk-3.2 → nltk-3.3}/nltk/test/translate.doctest +242 -242
- {nltk-3.2 → nltk-3.3}/nltk/test/translate_fixt.py +3 -3
- {nltk-3.2 → nltk-3.3}/nltk/test/tree.doctest +1101 -1101
- {nltk-3.2 → nltk-3.3}/nltk/test/treeprettyprinter.doctest +127 -127
- {nltk-3.2 → nltk-3.3}/nltk/test/treetransforms.doctest +156 -156
- nltk-3.3/nltk/test/unit/test_2x_compat.py +63 -0
- nltk-3.3/nltk/test/unit/test_aline.py +52 -0
- nltk-3.3/nltk/test/unit/test_chunk.py +56 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_classify.py +55 -53
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_collocations.py +88 -79
- nltk-3.3/nltk/test/unit/test_concordance.py +98 -0
- nltk-3.3/nltk/test/unit/test_corenlp.py +1000 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_corpora.py +200 -183
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_corpus_views.py +45 -45
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_hmm.py +88 -88
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_json2csv_corpus.py +188 -187
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_naivebayes.py +26 -26
- nltk-3.3/nltk/test/unit/test_rte_classify.py +86 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_seekable_unicode_stream_reader.py +124 -124
- nltk-3.3/nltk/test/unit/test_senna.py +74 -0
- nltk-3.3/nltk/test/unit/test_stem.py +121 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_tag.py +20 -20
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_tgrep.py +628 -626
- nltk-3.3/nltk/test/unit/test_tokenize.py +168 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_twitter_auth.py +185 -185
- nltk-3.3/nltk/test/unit/test_wordnet.py +134 -0
- nltk-3.3/nltk/test/unit/translate/test_bleu.py +244 -0
- nltk-3.3/nltk/test/unit/translate/test_gdfa.py +57 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm1.py +75 -75
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm2.py +87 -87
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm3.py +105 -105
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm4.py +126 -126
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm5.py +166 -166
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm_model.py +270 -270
- nltk-3.3/nltk/test/unit/translate/test_nist.py +37 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_stack_decoder.py +300 -300
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/utils.py +41 -41
- {nltk-3.2 → nltk-3.3}/nltk/test/util.doctest +48 -48
- {nltk-3.2 → nltk-3.3}/nltk/test/wordnet.doctest +595 -581
- {nltk-3.2 → nltk-3.3}/nltk/test/wordnet_fixt.py +7 -6
- {nltk-3.2 → nltk-3.3}/nltk/test/wordnet_lch.doctest +53 -53
- {nltk-3.2 → nltk-3.3}/nltk/test/wsd.doctest +68 -68
- {nltk-3.2 → nltk-3.3}/nltk/text.py +663 -610
- {nltk-3.2 → nltk-3.3}/nltk/tgrep.py +938 -937
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/__init__.py +130 -107
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/api.py +77 -78
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/casual.py +343 -342
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/mwe.py +120 -120
- nltk-3.3/nltk/tokenize/nist.py +173 -0
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/punkt.py +1620 -1601
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/regexp.py +208 -202
- nltk-3.3/nltk/tokenize/repp.py +151 -0
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/sexpr.py +140 -142
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/simple.py +138 -136
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/stanford.py +117 -113
- nltk-3.3/nltk/tokenize/stanford_segmenter.py +246 -0
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/texttiling.py +458 -460
- nltk-3.3/nltk/tokenize/toktok.py +155 -0
- nltk-3.3/nltk/tokenize/treebank.py +363 -0
- nltk-3.3/nltk/tokenize/util.py +261 -0
- {nltk-3.2 → nltk-3.3}/nltk/toolbox.py +499 -497
- {nltk-3.2 → nltk-3.3}/nltk/translate/__init__.py +24 -24
- {nltk-3.2 → nltk-3.3}/nltk/translate/api.py +331 -321
- {nltk-3.2 → nltk-3.3}/nltk/translate/bleu_score.py +615 -556
- nltk-3.3/nltk/translate/chrf_score.py +137 -0
- {nltk-3.2 → nltk-3.3}/nltk/translate/gale_church.py +248 -235
- {nltk-3.2 → nltk-3.3}/nltk/translate/gdfa.py +135 -131
- nltk-3.3/nltk/translate/gleu_score.py +193 -0
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm1.py +250 -241
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm2.py +308 -308
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm3.py +337 -337
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm4.py +467 -467
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm5.py +639 -639
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm_model.py +536 -533
- {nltk-3.2 → nltk-3.3}/nltk/translate/metrics.py +40 -40
- nltk-3.3/nltk/translate/nist_score.py +178 -0
- {nltk-3.2 → nltk-3.3}/nltk/translate/phrase_based.py +175 -175
- {nltk-3.2 → nltk-3.3}/nltk/translate/ribes_score.py +325 -325
- {nltk-3.2 → nltk-3.3}/nltk/translate/stack_decoder.py +499 -495
- {nltk-3.2 → nltk-3.3}/nltk/tree.py +1605 -1603
- {nltk-3.2 → nltk-3.3}/nltk/treeprettyprinter.py +564 -564
- {nltk-3.2 → nltk-3.3}/nltk/treetransforms.py +309 -309
- {nltk-3.2 → nltk-3.3}/nltk/twitter/__init__.py +28 -28
- {nltk-3.2 → nltk-3.3}/nltk/twitter/api.py +141 -136
- {nltk-3.2 → nltk-3.3}/nltk/twitter/common.py +264 -258
- {nltk-3.2 → nltk-3.3}/nltk/twitter/twitter_demo.py +288 -288
- {nltk-3.2 → nltk-3.3}/nltk/twitter/twitterclient.py +530 -530
- {nltk-3.2 → nltk-3.3}/nltk/twitter/util.py +147 -146
- nltk-3.3/nltk/util.py +751 -0
- {nltk-3.2 → nltk-3.3}/nltk/wsd.py +53 -53
- {nltk-3.2 → nltk-3.3/nltk.egg-info}/PKG-INFO +13 -5
- {nltk-3.2 → nltk-3.3}/nltk.egg-info/SOURCES.txt +26 -3
- nltk-3.3/nltk.egg-info/requires.txt +31 -0
- {nltk-3.2 → nltk-3.3}/setup.cfg +0 -1
- {nltk-3.2 → nltk-3.3}/setup.py +102 -75
- nltk-3.2/nltk/VERSION +0 -1
- nltk-3.2/nltk/compat.py +0 -680
- nltk-3.2/nltk/corpus/reader/pl196x.py +0 -278
- nltk-3.2/nltk/corpus/reader/verbnet.py +0 -408
- nltk-3.2/nltk/corpus/reader/wordlist.py +0 -37
- nltk-3.2/nltk/sentiment/vader_lexicon.txt +0 -7517
- nltk-3.2/nltk/six.py +0 -868
- nltk-3.2/nltk/stem/porter.py +0 -692
- nltk-3.2/nltk/test/unit/test_2x_compat.py +0 -26
- nltk-3.2/nltk/test/unit/test_stem.py +0 -36
- nltk-3.2/nltk/test/unit/test_tokenize.py +0 -23
- nltk-3.2/nltk/test/unit/translate/test_bleu.py +0 -84
- nltk-3.2/nltk/tokenize/treebank.py +0 -124
- nltk-3.2/nltk/tokenize/util.py +0 -90
- nltk-3.2/nltk/util.py +0 -1364
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/__init__.py +0 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/__init__.py +0 -0
- {nltk-3.2 → nltk-3.3}/nltk.egg-info/dependency_links.txt +0 -0
- {nltk-3.2 → nltk-3.3}/nltk.egg-info/not-zip-safe +0 -0
- {nltk-3.2 → nltk-3.3}/nltk.egg-info/top_level.txt +0 -0
|
@@ -1,607 +1,607 @@
|
|
|
1
|
-
# Natural Language Toolkit: First-Order Tableau Theorem Prover
|
|
2
|
-
#
|
|
3
|
-
# Copyright (C) 2001-
|
|
4
|
-
# Author: Dan Garrette <dhgarrette@gmail.com>
|
|
5
|
-
#
|
|
6
|
-
# URL: <http://nltk.org/>
|
|
7
|
-
# For license information, see LICENSE.TXT
|
|
8
|
-
|
|
9
|
-
"""
|
|
10
|
-
Module for a tableau-based First Order theorem prover.
|
|
11
|
-
"""
|
|
12
|
-
from __future__ import print_function, unicode_literals
|
|
13
|
-
|
|
14
|
-
from nltk.internals import Counter
|
|
15
|
-
|
|
16
|
-
from nltk.sem.logic import (VariableExpression, EqualityExpression,
|
|
17
|
-
ApplicationExpression, Expression,
|
|
18
|
-
AbstractVariableExpression, AllExpression,
|
|
19
|
-
NegatedExpression,
|
|
20
|
-
ExistsExpression, Variable, ImpExpression,
|
|
21
|
-
AndExpression, unique_variable,
|
|
22
|
-
LambdaExpression, IffExpression,
|
|
23
|
-
OrExpression, FunctionVariableExpression)
|
|
24
|
-
|
|
25
|
-
from nltk.inference.api import Prover, BaseProverCommand
|
|
26
|
-
|
|
27
|
-
_counter = Counter()
|
|
28
|
-
|
|
29
|
-
class ProverParseError(Exception): pass
|
|
30
|
-
|
|
31
|
-
class TableauProver(Prover):
|
|
32
|
-
_assume_false=False
|
|
33
|
-
|
|
34
|
-
def _prove(self, goal=None, assumptions=None, verbose=False):
|
|
35
|
-
if not assumptions:
|
|
36
|
-
assumptions = []
|
|
37
|
-
|
|
38
|
-
result = None
|
|
39
|
-
try:
|
|
40
|
-
agenda = Agenda()
|
|
41
|
-
if goal:
|
|
42
|
-
agenda.put(-goal)
|
|
43
|
-
agenda.put_all(assumptions)
|
|
44
|
-
debugger = Debug(verbose)
|
|
45
|
-
result = self._attempt_proof(agenda, set(), set(), debugger)
|
|
46
|
-
except RuntimeError as e:
|
|
47
|
-
if self._assume_false and str(e).startswith('maximum recursion depth exceeded'):
|
|
48
|
-
result = False
|
|
49
|
-
else:
|
|
50
|
-
if verbose:
|
|
51
|
-
print(e)
|
|
52
|
-
else:
|
|
53
|
-
raise e
|
|
54
|
-
return (result, '\n'.join(debugger.lines))
|
|
55
|
-
|
|
56
|
-
def _attempt_proof(self, agenda, accessible_vars, atoms, debug):
|
|
57
|
-
(current, context), category = agenda.pop_first()
|
|
58
|
-
|
|
59
|
-
#if there's nothing left in the agenda, and we haven't closed the path
|
|
60
|
-
if not current:
|
|
61
|
-
debug.line('AGENDA EMPTY')
|
|
62
|
-
return False
|
|
63
|
-
|
|
64
|
-
proof_method = { Categories.ATOM: self._attempt_proof_atom,
|
|
65
|
-
Categories.PROP: self._attempt_proof_prop,
|
|
66
|
-
Categories.N_ATOM: self._attempt_proof_n_atom,
|
|
67
|
-
Categories.N_PROP: self._attempt_proof_n_prop,
|
|
68
|
-
Categories.APP: self._attempt_proof_app,
|
|
69
|
-
Categories.N_APP: self._attempt_proof_n_app,
|
|
70
|
-
Categories.N_EQ: self._attempt_proof_n_eq,
|
|
71
|
-
Categories.D_NEG: self._attempt_proof_d_neg,
|
|
72
|
-
Categories.N_ALL: self._attempt_proof_n_all,
|
|
73
|
-
Categories.N_EXISTS: self._attempt_proof_n_some,
|
|
74
|
-
Categories.AND: self._attempt_proof_and,
|
|
75
|
-
Categories.N_OR: self._attempt_proof_n_or,
|
|
76
|
-
Categories.N_IMP: self._attempt_proof_n_imp,
|
|
77
|
-
Categories.OR: self._attempt_proof_or,
|
|
78
|
-
Categories.IMP: self._attempt_proof_imp,
|
|
79
|
-
Categories.N_AND: self._attempt_proof_n_and,
|
|
80
|
-
Categories.IFF: self._attempt_proof_iff,
|
|
81
|
-
Categories.N_IFF: self._attempt_proof_n_iff,
|
|
82
|
-
Categories.EQ: self._attempt_proof_eq,
|
|
83
|
-
Categories.EXISTS: self._attempt_proof_some,
|
|
84
|
-
Categories.ALL: self._attempt_proof_all,
|
|
85
|
-
}[category]
|
|
86
|
-
|
|
87
|
-
debug.line((current, context))
|
|
88
|
-
return proof_method(current, context, agenda, accessible_vars, atoms, debug)
|
|
89
|
-
|
|
90
|
-
def _attempt_proof_atom(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
91
|
-
# Check if the branch is closed. Return 'True' if it is
|
|
92
|
-
if (current, True) in atoms:
|
|
93
|
-
debug.line('CLOSED', 1)
|
|
94
|
-
return True
|
|
95
|
-
|
|
96
|
-
if context:
|
|
97
|
-
if isinstance(context.term, NegatedExpression):
|
|
98
|
-
current = current.negate()
|
|
99
|
-
agenda.put(context(current).simplify())
|
|
100
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
101
|
-
else:
|
|
102
|
-
#mark all AllExpressions as 'not exhausted' into the agenda since we are (potentially) adding new accessible vars
|
|
103
|
-
agenda.mark_alls_fresh();
|
|
104
|
-
return self._attempt_proof(agenda, accessible_vars|set(current.args), atoms|set([(current, False)]), debug+1)
|
|
105
|
-
|
|
106
|
-
def _attempt_proof_n_atom(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
107
|
-
# Check if the branch is closed. Return 'True' if it is
|
|
108
|
-
if (current.term, False) in atoms:
|
|
109
|
-
debug.line('CLOSED', 1)
|
|
110
|
-
return True
|
|
111
|
-
|
|
112
|
-
if context:
|
|
113
|
-
if isinstance(context.term, NegatedExpression):
|
|
114
|
-
current = current.negate()
|
|
115
|
-
agenda.put(context(current).simplify())
|
|
116
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
117
|
-
else:
|
|
118
|
-
#mark all AllExpressions as 'not exhausted' into the agenda since we are (potentially) adding new accessible vars
|
|
119
|
-
agenda.mark_alls_fresh();
|
|
120
|
-
return self._attempt_proof(agenda, accessible_vars|set(current.term.args), atoms|set([(current.term, True)]), debug+1)
|
|
121
|
-
|
|
122
|
-
def _attempt_proof_prop(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
123
|
-
# Check if the branch is closed. Return 'True' if it is
|
|
124
|
-
if (current, True) in atoms:
|
|
125
|
-
debug.line('CLOSED', 1)
|
|
126
|
-
return True
|
|
127
|
-
|
|
128
|
-
#mark all AllExpressions as 'not exhausted' into the agenda since we are (potentially) adding new accessible vars
|
|
129
|
-
agenda.mark_alls_fresh();
|
|
130
|
-
return self._attempt_proof(agenda, accessible_vars, atoms|set([(current, False)]), debug+1)
|
|
131
|
-
|
|
132
|
-
def _attempt_proof_n_prop(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
133
|
-
# Check if the branch is closed. Return 'True' if it is
|
|
134
|
-
if (current.term, False) in atoms:
|
|
135
|
-
debug.line('CLOSED', 1)
|
|
136
|
-
return True
|
|
137
|
-
|
|
138
|
-
#mark all AllExpressions as 'not exhausted' into the agenda since we are (potentially) adding new accessible vars
|
|
139
|
-
agenda.mark_alls_fresh();
|
|
140
|
-
return self._attempt_proof(agenda, accessible_vars, atoms|set([(current.term, True)]), debug+1)
|
|
141
|
-
|
|
142
|
-
def _attempt_proof_app(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
143
|
-
f, args = current.uncurry()
|
|
144
|
-
for i, arg in enumerate(args):
|
|
145
|
-
if not TableauProver.is_atom(arg):
|
|
146
|
-
ctx = f
|
|
147
|
-
nv = Variable('X%s' % _counter.get())
|
|
148
|
-
for j,a in enumerate(args):
|
|
149
|
-
ctx = (ctx(VariableExpression(nv)) if i == j else ctx(a))
|
|
150
|
-
if context:
|
|
151
|
-
ctx = context(ctx).simplify()
|
|
152
|
-
ctx = LambdaExpression(nv, ctx)
|
|
153
|
-
agenda.put(arg, ctx)
|
|
154
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
155
|
-
raise Exception('If this method is called, there must be a non-atomic argument')
|
|
156
|
-
|
|
157
|
-
def _attempt_proof_n_app(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
158
|
-
f, args = current.term.uncurry()
|
|
159
|
-
for i, arg in enumerate(args):
|
|
160
|
-
if not TableauProver.is_atom(arg):
|
|
161
|
-
ctx = f
|
|
162
|
-
nv = Variable('X%s' % _counter.get())
|
|
163
|
-
for j,a in enumerate(args):
|
|
164
|
-
ctx = (ctx(VariableExpression(nv)) if i == j else ctx(a))
|
|
165
|
-
if context:
|
|
166
|
-
#combine new context with existing
|
|
167
|
-
ctx = context(ctx).simplify()
|
|
168
|
-
ctx = LambdaExpression(nv, -ctx)
|
|
169
|
-
agenda.put(-arg, ctx)
|
|
170
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
171
|
-
raise Exception('If this method is called, there must be a non-atomic argument')
|
|
172
|
-
|
|
173
|
-
def _attempt_proof_n_eq(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
174
|
-
###########################################################################
|
|
175
|
-
# Since 'current' is of type '~(a=b)', the path is closed if 'a' == 'b'
|
|
176
|
-
###########################################################################
|
|
177
|
-
if current.term.first == current.term.second:
|
|
178
|
-
debug.line('CLOSED', 1)
|
|
179
|
-
return True
|
|
180
|
-
|
|
181
|
-
agenda[Categories.N_EQ].add((current,context))
|
|
182
|
-
current._exhausted = True
|
|
183
|
-
return self._attempt_proof(agenda, accessible_vars|set([current.term.first, current.term.second]), atoms, debug+1)
|
|
184
|
-
|
|
185
|
-
def _attempt_proof_d_neg(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
186
|
-
agenda.put(current.term.term, context)
|
|
187
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
188
|
-
|
|
189
|
-
def _attempt_proof_n_all(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
190
|
-
agenda[Categories.EXISTS].add((ExistsExpression(current.term.variable, -current.term.term), context))
|
|
191
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
192
|
-
|
|
193
|
-
def _attempt_proof_n_some(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
194
|
-
agenda[Categories.ALL].add((AllExpression(current.term.variable, -current.term.term), context))
|
|
195
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
196
|
-
|
|
197
|
-
def _attempt_proof_and(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
198
|
-
agenda.put(current.first, context)
|
|
199
|
-
agenda.put(current.second, context)
|
|
200
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
201
|
-
|
|
202
|
-
def _attempt_proof_n_or(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
203
|
-
agenda.put(-current.term.first, context)
|
|
204
|
-
agenda.put(-current.term.second, context)
|
|
205
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
206
|
-
|
|
207
|
-
def _attempt_proof_n_imp(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
208
|
-
agenda.put(current.term.first, context)
|
|
209
|
-
agenda.put(-current.term.second, context)
|
|
210
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
211
|
-
|
|
212
|
-
def _attempt_proof_or(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
213
|
-
new_agenda = agenda.clone()
|
|
214
|
-
agenda.put(current.first, context)
|
|
215
|
-
new_agenda.put(current.second, context)
|
|
216
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1) and \
|
|
217
|
-
self._attempt_proof(new_agenda, accessible_vars, atoms, debug+1)
|
|
218
|
-
|
|
219
|
-
def _attempt_proof_imp(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
220
|
-
new_agenda = agenda.clone()
|
|
221
|
-
agenda.put(-current.first, context)
|
|
222
|
-
new_agenda.put(current.second, context)
|
|
223
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1) and \
|
|
224
|
-
self._attempt_proof(new_agenda, accessible_vars, atoms, debug+1)
|
|
225
|
-
|
|
226
|
-
def _attempt_proof_n_and(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
227
|
-
new_agenda = agenda.clone()
|
|
228
|
-
agenda.put(-current.term.first, context)
|
|
229
|
-
new_agenda.put(-current.term.second, context)
|
|
230
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1) and \
|
|
231
|
-
self._attempt_proof(new_agenda, accessible_vars, atoms, debug+1)
|
|
232
|
-
|
|
233
|
-
def _attempt_proof_iff(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
234
|
-
new_agenda = agenda.clone()
|
|
235
|
-
agenda.put(current.first, context)
|
|
236
|
-
agenda.put(current.second, context)
|
|
237
|
-
new_agenda.put(-current.first, context)
|
|
238
|
-
new_agenda.put(-current.second, context)
|
|
239
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1) and \
|
|
240
|
-
self._attempt_proof(new_agenda, accessible_vars, atoms, debug+1)
|
|
241
|
-
|
|
242
|
-
def _attempt_proof_n_iff(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
243
|
-
new_agenda = agenda.clone()
|
|
244
|
-
agenda.put(current.term.first, context)
|
|
245
|
-
agenda.put(-current.term.second, context)
|
|
246
|
-
new_agenda.put(-current.term.first, context)
|
|
247
|
-
new_agenda.put(current.term.second, context)
|
|
248
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1) and \
|
|
249
|
-
self._attempt_proof(new_agenda, accessible_vars, atoms, debug+1)
|
|
250
|
-
|
|
251
|
-
def _attempt_proof_eq(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
252
|
-
#########################################################################
|
|
253
|
-
# Since 'current' is of the form '(a = b)', replace ALL free instances
|
|
254
|
-
# of 'a' with 'b'
|
|
255
|
-
#########################################################################
|
|
256
|
-
agenda.put_atoms(atoms)
|
|
257
|
-
agenda.replace_all(current.first, current.second)
|
|
258
|
-
accessible_vars.discard(current.first)
|
|
259
|
-
agenda.mark_neqs_fresh();
|
|
260
|
-
return self._attempt_proof(agenda, accessible_vars, set(), debug+1)
|
|
261
|
-
|
|
262
|
-
def _attempt_proof_some(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
263
|
-
new_unique_variable = VariableExpression(unique_variable())
|
|
264
|
-
agenda.put(current.term.replace(current.variable, new_unique_variable), context)
|
|
265
|
-
agenda.mark_alls_fresh()
|
|
266
|
-
return self._attempt_proof(agenda, accessible_vars|set([new_unique_variable]), atoms, debug+1)
|
|
267
|
-
|
|
268
|
-
def _attempt_proof_all(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
269
|
-
try:
|
|
270
|
-
current._used_vars
|
|
271
|
-
except AttributeError:
|
|
272
|
-
current._used_vars = set()
|
|
273
|
-
|
|
274
|
-
#if there are accessible_vars on the path
|
|
275
|
-
if accessible_vars:
|
|
276
|
-
# get the set of bound variables that have not be used by this AllExpression
|
|
277
|
-
bv_available = accessible_vars - current._used_vars
|
|
278
|
-
|
|
279
|
-
if bv_available:
|
|
280
|
-
variable_to_use = list(bv_available)[0]
|
|
281
|
-
debug.line('--> Using \'%s\'' % variable_to_use, 2)
|
|
282
|
-
current._used_vars |= set([variable_to_use])
|
|
283
|
-
agenda.put(current.term.replace(current.variable, variable_to_use), context)
|
|
284
|
-
agenda[Categories.ALL].add((current,context))
|
|
285
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
286
|
-
|
|
287
|
-
else:
|
|
288
|
-
#no more available variables to substitute
|
|
289
|
-
debug.line('--> Variables Exhausted', 2)
|
|
290
|
-
current._exhausted = True
|
|
291
|
-
agenda[Categories.ALL].add((current,context))
|
|
292
|
-
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
293
|
-
|
|
294
|
-
else:
|
|
295
|
-
new_unique_variable = VariableExpression(unique_variable())
|
|
296
|
-
debug.line('--> Using \'%s\'' % new_unique_variable, 2)
|
|
297
|
-
current._used_vars |= set([new_unique_variable])
|
|
298
|
-
agenda.put(current.term.replace(current.variable, new_unique_variable), context)
|
|
299
|
-
agenda[Categories.ALL].add((current,context))
|
|
300
|
-
agenda.mark_alls_fresh()
|
|
301
|
-
return self._attempt_proof(agenda, accessible_vars|set([new_unique_variable]), atoms, debug+1)
|
|
302
|
-
|
|
303
|
-
@staticmethod
|
|
304
|
-
def is_atom(e):
|
|
305
|
-
if isinstance(e, NegatedExpression):
|
|
306
|
-
e = e.term
|
|
307
|
-
|
|
308
|
-
if isinstance(e, ApplicationExpression):
|
|
309
|
-
for arg in e.args:
|
|
310
|
-
if not TableauProver.is_atom(arg):
|
|
311
|
-
return False
|
|
312
|
-
return True
|
|
313
|
-
elif isinstance(e, AbstractVariableExpression) or \
|
|
314
|
-
isinstance(e, LambdaExpression):
|
|
315
|
-
return True
|
|
316
|
-
else:
|
|
317
|
-
return False
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
class TableauProverCommand(BaseProverCommand):
|
|
321
|
-
def __init__(self, goal=None, assumptions=None, prover=None):
|
|
322
|
-
"""
|
|
323
|
-
:param goal: Input expression to prove
|
|
324
|
-
:type goal: sem.Expression
|
|
325
|
-
:param assumptions: Input expressions to use as assumptions in
|
|
326
|
-
the proof.
|
|
327
|
-
:type assumptions: list(sem.Expression)
|
|
328
|
-
"""
|
|
329
|
-
if prover is not None:
|
|
330
|
-
assert isinstance(prover, TableauProver)
|
|
331
|
-
else:
|
|
332
|
-
prover = TableauProver()
|
|
333
|
-
|
|
334
|
-
BaseProverCommand.__init__(self, prover, goal, assumptions)
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
class Agenda(object):
|
|
338
|
-
def __init__(self):
|
|
339
|
-
self.sets = tuple(set() for i in range(21))
|
|
340
|
-
|
|
341
|
-
def clone(self):
|
|
342
|
-
new_agenda = Agenda()
|
|
343
|
-
set_list = [s.copy() for s in self.sets]
|
|
344
|
-
|
|
345
|
-
new_allExs = set()
|
|
346
|
-
for allEx,_ in set_list[Categories.ALL]:
|
|
347
|
-
new_allEx = AllExpression(allEx.variable, allEx.term)
|
|
348
|
-
try:
|
|
349
|
-
new_allEx._used_vars = set(used for used in allEx._used_vars)
|
|
350
|
-
except AttributeError:
|
|
351
|
-
new_allEx._used_vars = set()
|
|
352
|
-
new_allExs.add((new_allEx,None))
|
|
353
|
-
set_list[Categories.ALL] = new_allExs
|
|
354
|
-
|
|
355
|
-
set_list[Categories.N_EQ] = set((NegatedExpression(n_eq.term),ctx)
|
|
356
|
-
for (n_eq,ctx) in set_list[Categories.N_EQ])
|
|
357
|
-
|
|
358
|
-
new_agenda.sets = tuple(set_list)
|
|
359
|
-
return new_agenda
|
|
360
|
-
|
|
361
|
-
def __getitem__(self, index):
|
|
362
|
-
return self.sets[index]
|
|
363
|
-
|
|
364
|
-
def put(self, expression, context=None):
|
|
365
|
-
if isinstance(expression, AllExpression):
|
|
366
|
-
ex_to_add = AllExpression(expression.variable, expression.term)
|
|
367
|
-
try:
|
|
368
|
-
ex_to_add._used_vars = set(used for used in expression._used_vars)
|
|
369
|
-
except AttributeError:
|
|
370
|
-
ex_to_add._used_vars = set()
|
|
371
|
-
else:
|
|
372
|
-
ex_to_add = expression
|
|
373
|
-
self.sets[self._categorize_expression(ex_to_add)].add((ex_to_add, context))
|
|
374
|
-
|
|
375
|
-
def put_all(self, expressions):
|
|
376
|
-
for expression in expressions:
|
|
377
|
-
self.put(expression)
|
|
378
|
-
|
|
379
|
-
def put_atoms(self, atoms):
|
|
380
|
-
for atom, neg in atoms:
|
|
381
|
-
if neg:
|
|
382
|
-
self[Categories.N_ATOM].add((-atom,None))
|
|
383
|
-
else:
|
|
384
|
-
self[Categories.ATOM].add((atom,None))
|
|
385
|
-
|
|
386
|
-
def pop_first(self):
|
|
387
|
-
""" Pop the first expression that appears in the agenda """
|
|
388
|
-
for i,s in enumerate(self.sets):
|
|
389
|
-
if s:
|
|
390
|
-
if i in [Categories.N_EQ, Categories.ALL]:
|
|
391
|
-
for ex in s:
|
|
392
|
-
try:
|
|
393
|
-
if not ex[0]._exhausted:
|
|
394
|
-
s.remove(ex)
|
|
395
|
-
return (ex, i)
|
|
396
|
-
except AttributeError:
|
|
397
|
-
s.remove(ex)
|
|
398
|
-
return (ex, i)
|
|
399
|
-
else:
|
|
400
|
-
return (s.pop(), i)
|
|
401
|
-
return ((None, None), None)
|
|
402
|
-
|
|
403
|
-
def replace_all(self, old, new):
|
|
404
|
-
for s in self.sets:
|
|
405
|
-
for ex,ctx in s:
|
|
406
|
-
ex.replace(old.variable, new)
|
|
407
|
-
if ctx is not None:
|
|
408
|
-
ctx.replace(old.variable, new)
|
|
409
|
-
|
|
410
|
-
def mark_alls_fresh(self):
|
|
411
|
-
for u,_ in self.sets[Categories.ALL]:
|
|
412
|
-
u._exhausted = False
|
|
413
|
-
|
|
414
|
-
def mark_neqs_fresh(self):
|
|
415
|
-
for neq,_ in self.sets[Categories.N_EQ]:
|
|
416
|
-
neq._exhausted = False
|
|
417
|
-
|
|
418
|
-
def _categorize_expression(self, current):
|
|
419
|
-
if isinstance(current, NegatedExpression):
|
|
420
|
-
return self._categorize_NegatedExpression(current)
|
|
421
|
-
elif isinstance(current, FunctionVariableExpression):
|
|
422
|
-
return Categories.PROP
|
|
423
|
-
elif TableauProver.is_atom(current):
|
|
424
|
-
return Categories.ATOM
|
|
425
|
-
elif isinstance(current, AllExpression):
|
|
426
|
-
return Categories.ALL
|
|
427
|
-
elif isinstance(current, AndExpression):
|
|
428
|
-
return Categories.AND
|
|
429
|
-
elif isinstance(current, OrExpression):
|
|
430
|
-
return Categories.OR
|
|
431
|
-
elif isinstance(current, ImpExpression):
|
|
432
|
-
return Categories.IMP
|
|
433
|
-
elif isinstance(current, IffExpression):
|
|
434
|
-
return Categories.IFF
|
|
435
|
-
elif isinstance(current, EqualityExpression):
|
|
436
|
-
return Categories.EQ
|
|
437
|
-
elif isinstance(current, ExistsExpression):
|
|
438
|
-
return Categories.EXISTS
|
|
439
|
-
elif isinstance(current, ApplicationExpression):
|
|
440
|
-
return Categories.APP
|
|
441
|
-
else:
|
|
442
|
-
raise ProverParseError("cannot categorize %s" % \
|
|
443
|
-
current.__class__.__name__)
|
|
444
|
-
|
|
445
|
-
def _categorize_NegatedExpression(self, current):
|
|
446
|
-
negated = current.term
|
|
447
|
-
|
|
448
|
-
if isinstance(negated, NegatedExpression):
|
|
449
|
-
return Categories.D_NEG
|
|
450
|
-
elif isinstance(negated, FunctionVariableExpression):
|
|
451
|
-
return Categories.N_PROP
|
|
452
|
-
elif TableauProver.is_atom(negated):
|
|
453
|
-
return Categories.N_ATOM
|
|
454
|
-
elif isinstance(negated, AllExpression):
|
|
455
|
-
return Categories.N_ALL
|
|
456
|
-
elif isinstance(negated, AndExpression):
|
|
457
|
-
return Categories.N_AND
|
|
458
|
-
elif isinstance(negated, OrExpression):
|
|
459
|
-
return Categories.N_OR
|
|
460
|
-
elif isinstance(negated, ImpExpression):
|
|
461
|
-
return Categories.N_IMP
|
|
462
|
-
elif isinstance(negated, IffExpression):
|
|
463
|
-
return Categories.N_IFF
|
|
464
|
-
elif isinstance(negated, EqualityExpression):
|
|
465
|
-
return Categories.N_EQ
|
|
466
|
-
elif isinstance(negated, ExistsExpression):
|
|
467
|
-
return Categories.N_EXISTS
|
|
468
|
-
elif isinstance(negated, ApplicationExpression):
|
|
469
|
-
return Categories.N_APP
|
|
470
|
-
else:
|
|
471
|
-
raise ProverParseError("cannot categorize %s" % \
|
|
472
|
-
negated.__class__.__name__)
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
class Debug(object):
|
|
476
|
-
def __init__(self, verbose, indent=0, lines=None):
|
|
477
|
-
self.verbose = verbose
|
|
478
|
-
self.indent = indent
|
|
479
|
-
|
|
480
|
-
if not lines: lines = []
|
|
481
|
-
self.lines = lines
|
|
482
|
-
|
|
483
|
-
def __add__(self, increment):
|
|
484
|
-
return Debug(self.verbose, self.indent+1, self.lines)
|
|
485
|
-
|
|
486
|
-
def line(self, data, indent=0):
|
|
487
|
-
if isinstance(data, tuple):
|
|
488
|
-
ex, ctx = data
|
|
489
|
-
if ctx:
|
|
490
|
-
data = '%s, %s' % (ex, ctx)
|
|
491
|
-
else:
|
|
492
|
-
data = '%s' % ex
|
|
493
|
-
|
|
494
|
-
if isinstance(ex, AllExpression):
|
|
495
|
-
try:
|
|
496
|
-
used_vars = "[%s]" % (",".join("%s" % ve.variable.name for ve in ex._used_vars))
|
|
497
|
-
data += ': %s' % used_vars
|
|
498
|
-
except AttributeError:
|
|
499
|
-
data += ': []'
|
|
500
|
-
|
|
501
|
-
newline = '%s%s' % (' '*(self.indent+indent), data)
|
|
502
|
-
self.lines.append(newline)
|
|
503
|
-
|
|
504
|
-
if self.verbose:
|
|
505
|
-
print(newline)
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
class Categories(object):
|
|
509
|
-
ATOM = 0
|
|
510
|
-
PROP = 1
|
|
511
|
-
N_ATOM = 2
|
|
512
|
-
N_PROP = 3
|
|
513
|
-
APP = 4
|
|
514
|
-
N_APP = 5
|
|
515
|
-
N_EQ = 6
|
|
516
|
-
D_NEG = 7
|
|
517
|
-
N_ALL = 8
|
|
518
|
-
N_EXISTS = 9
|
|
519
|
-
AND = 10
|
|
520
|
-
N_OR = 11
|
|
521
|
-
N_IMP = 12
|
|
522
|
-
OR = 13
|
|
523
|
-
IMP = 14
|
|
524
|
-
N_AND = 15
|
|
525
|
-
IFF = 16
|
|
526
|
-
N_IFF = 17
|
|
527
|
-
EQ = 18
|
|
528
|
-
EXISTS = 19
|
|
529
|
-
ALL = 20
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
def testTableauProver():
|
|
533
|
-
tableau_test('P | -P')
|
|
534
|
-
tableau_test('P & -P')
|
|
535
|
-
tableau_test('Q', ['P', '(P -> Q)'])
|
|
536
|
-
tableau_test('man(x)')
|
|
537
|
-
tableau_test('(man(x) -> man(x))')
|
|
538
|
-
tableau_test('(man(x) -> --man(x))')
|
|
539
|
-
tableau_test('-(man(x) and -man(x))')
|
|
540
|
-
tableau_test('(man(x) or -man(x))')
|
|
541
|
-
tableau_test('(man(x) -> man(x))')
|
|
542
|
-
tableau_test('-(man(x) and -man(x))')
|
|
543
|
-
tableau_test('(man(x) or -man(x))')
|
|
544
|
-
tableau_test('(man(x) -> man(x))')
|
|
545
|
-
tableau_test('(man(x) iff man(x))')
|
|
546
|
-
tableau_test('-(man(x) iff -man(x))')
|
|
547
|
-
tableau_test('all x.man(x)')
|
|
548
|
-
tableau_test('all x.all y.((x = y) -> (y = x))')
|
|
549
|
-
tableau_test('all x.all y.all z.(((x = y) & (y = z)) -> (x = z))')
|
|
550
|
-
# tableau_test('-all x.some y.F(x,y) & some x.all y.(-F(x,y))')
|
|
551
|
-
# tableau_test('some x.all y.sees(x,y)')
|
|
552
|
-
|
|
553
|
-
p1 = 'all x.(man(x) -> mortal(x))'
|
|
554
|
-
p2 = 'man(Socrates)'
|
|
555
|
-
c = 'mortal(Socrates)'
|
|
556
|
-
tableau_test(c, [p1, p2])
|
|
557
|
-
|
|
558
|
-
p1 = 'all x.(man(x) -> walks(x))'
|
|
559
|
-
p2 = 'man(John)'
|
|
560
|
-
c = 'some y.walks(y)'
|
|
561
|
-
tableau_test(c, [p1, p2])
|
|
562
|
-
|
|
563
|
-
p = '((x = y) & walks(y))'
|
|
564
|
-
c = 'walks(x)'
|
|
565
|
-
tableau_test(c, [p])
|
|
566
|
-
|
|
567
|
-
p = '((x = y) & ((y = z) & (z = w)))'
|
|
568
|
-
c = '(x = w)'
|
|
569
|
-
tableau_test(c, [p])
|
|
570
|
-
|
|
571
|
-
p = 'some e1.some e2.(believe(e1,john,e2) & walk(e2,mary))'
|
|
572
|
-
c = 'some e0.walk(e0,mary)'
|
|
573
|
-
tableau_test(c, [p])
|
|
574
|
-
|
|
575
|
-
c = '(exists x.exists z3.((x = Mary) & ((z3 = John) & sees(z3,x))) <-> exists x.exists z4.((x = John) & ((z4 = Mary) & sees(x,z4))))'
|
|
576
|
-
tableau_test(c)
|
|
577
|
-
|
|
578
|
-
# p = 'some e1.some e2.((believe e1 john e2) and (walk e2 mary))'
|
|
579
|
-
# c = 'some x.some e3.some e4.((believe e3 x e4) and (walk e4 mary))'
|
|
580
|
-
# tableau_test(c, [p])
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
def testHigherOrderTableauProver():
|
|
584
|
-
tableau_test('believe(j, -lie(b))', ['believe(j, -lie(b) & -cheat(b))'])
|
|
585
|
-
tableau_test('believe(j, lie(b) & cheat(b))', ['believe(j, lie(b))'])
|
|
586
|
-
tableau_test('believe(j, lie(b))', ['lie(b)']) #how do we capture that John believes all things that are true
|
|
587
|
-
tableau_test('believe(j, know(b, cheat(b)))', ['believe(j, know(b, lie(b)) & know(b, steals(b) & cheat(b)))'])
|
|
588
|
-
tableau_test('P(Q(y), R(y) & R(z))', ['P(Q(x) & Q(y), R(y) & R(z))'])
|
|
589
|
-
|
|
590
|
-
tableau_test('believe(j, cheat(b) & lie(b))', ['believe(j, lie(b) & cheat(b))'])
|
|
591
|
-
tableau_test('believe(j, -cheat(b) & -lie(b))', ['believe(j, -lie(b) & -cheat(b))'])
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
def tableau_test(c, ps=None, verbose=False):
|
|
595
|
-
pc = Expression.fromstring(c)
|
|
596
|
-
pps = ([Expression.fromstring(p) for p in ps] if ps else [])
|
|
597
|
-
if not ps:
|
|
598
|
-
ps = []
|
|
599
|
-
print('%s |- %s: %s' % (', '.join(ps), pc, TableauProver().prove(pc, pps, verbose=verbose)))
|
|
600
|
-
|
|
601
|
-
def demo():
|
|
602
|
-
testTableauProver()
|
|
603
|
-
testHigherOrderTableauProver()
|
|
604
|
-
|
|
605
|
-
if __name__ == '__main__':
|
|
606
|
-
demo()
|
|
607
|
-
|
|
1
|
+
# Natural Language Toolkit: First-Order Tableau Theorem Prover
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2001-2018 NLTK Project
|
|
4
|
+
# Author: Dan Garrette <dhgarrette@gmail.com>
|
|
5
|
+
#
|
|
6
|
+
# URL: <http://nltk.org/>
|
|
7
|
+
# For license information, see LICENSE.TXT
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
Module for a tableau-based First Order theorem prover.
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import print_function, unicode_literals
|
|
13
|
+
|
|
14
|
+
from nltk.internals import Counter
|
|
15
|
+
|
|
16
|
+
from nltk.sem.logic import (VariableExpression, EqualityExpression,
|
|
17
|
+
ApplicationExpression, Expression,
|
|
18
|
+
AbstractVariableExpression, AllExpression,
|
|
19
|
+
NegatedExpression,
|
|
20
|
+
ExistsExpression, Variable, ImpExpression,
|
|
21
|
+
AndExpression, unique_variable,
|
|
22
|
+
LambdaExpression, IffExpression,
|
|
23
|
+
OrExpression, FunctionVariableExpression)
|
|
24
|
+
|
|
25
|
+
from nltk.inference.api import Prover, BaseProverCommand
|
|
26
|
+
|
|
27
|
+
_counter = Counter()
|
|
28
|
+
|
|
29
|
+
class ProverParseError(Exception): pass
|
|
30
|
+
|
|
31
|
+
class TableauProver(Prover):
|
|
32
|
+
_assume_false=False
|
|
33
|
+
|
|
34
|
+
def _prove(self, goal=None, assumptions=None, verbose=False):
|
|
35
|
+
if not assumptions:
|
|
36
|
+
assumptions = []
|
|
37
|
+
|
|
38
|
+
result = None
|
|
39
|
+
try:
|
|
40
|
+
agenda = Agenda()
|
|
41
|
+
if goal:
|
|
42
|
+
agenda.put(-goal)
|
|
43
|
+
agenda.put_all(assumptions)
|
|
44
|
+
debugger = Debug(verbose)
|
|
45
|
+
result = self._attempt_proof(agenda, set(), set(), debugger)
|
|
46
|
+
except RuntimeError as e:
|
|
47
|
+
if self._assume_false and str(e).startswith('maximum recursion depth exceeded'):
|
|
48
|
+
result = False
|
|
49
|
+
else:
|
|
50
|
+
if verbose:
|
|
51
|
+
print(e)
|
|
52
|
+
else:
|
|
53
|
+
raise e
|
|
54
|
+
return (result, '\n'.join(debugger.lines))
|
|
55
|
+
|
|
56
|
+
def _attempt_proof(self, agenda, accessible_vars, atoms, debug):
|
|
57
|
+
(current, context), category = agenda.pop_first()
|
|
58
|
+
|
|
59
|
+
#if there's nothing left in the agenda, and we haven't closed the path
|
|
60
|
+
if not current:
|
|
61
|
+
debug.line('AGENDA EMPTY')
|
|
62
|
+
return False
|
|
63
|
+
|
|
64
|
+
proof_method = { Categories.ATOM: self._attempt_proof_atom,
|
|
65
|
+
Categories.PROP: self._attempt_proof_prop,
|
|
66
|
+
Categories.N_ATOM: self._attempt_proof_n_atom,
|
|
67
|
+
Categories.N_PROP: self._attempt_proof_n_prop,
|
|
68
|
+
Categories.APP: self._attempt_proof_app,
|
|
69
|
+
Categories.N_APP: self._attempt_proof_n_app,
|
|
70
|
+
Categories.N_EQ: self._attempt_proof_n_eq,
|
|
71
|
+
Categories.D_NEG: self._attempt_proof_d_neg,
|
|
72
|
+
Categories.N_ALL: self._attempt_proof_n_all,
|
|
73
|
+
Categories.N_EXISTS: self._attempt_proof_n_some,
|
|
74
|
+
Categories.AND: self._attempt_proof_and,
|
|
75
|
+
Categories.N_OR: self._attempt_proof_n_or,
|
|
76
|
+
Categories.N_IMP: self._attempt_proof_n_imp,
|
|
77
|
+
Categories.OR: self._attempt_proof_or,
|
|
78
|
+
Categories.IMP: self._attempt_proof_imp,
|
|
79
|
+
Categories.N_AND: self._attempt_proof_n_and,
|
|
80
|
+
Categories.IFF: self._attempt_proof_iff,
|
|
81
|
+
Categories.N_IFF: self._attempt_proof_n_iff,
|
|
82
|
+
Categories.EQ: self._attempt_proof_eq,
|
|
83
|
+
Categories.EXISTS: self._attempt_proof_some,
|
|
84
|
+
Categories.ALL: self._attempt_proof_all,
|
|
85
|
+
}[category]
|
|
86
|
+
|
|
87
|
+
debug.line((current, context))
|
|
88
|
+
return proof_method(current, context, agenda, accessible_vars, atoms, debug)
|
|
89
|
+
|
|
90
|
+
def _attempt_proof_atom(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
91
|
+
# Check if the branch is closed. Return 'True' if it is
|
|
92
|
+
if (current, True) in atoms:
|
|
93
|
+
debug.line('CLOSED', 1)
|
|
94
|
+
return True
|
|
95
|
+
|
|
96
|
+
if context:
|
|
97
|
+
if isinstance(context.term, NegatedExpression):
|
|
98
|
+
current = current.negate()
|
|
99
|
+
agenda.put(context(current).simplify())
|
|
100
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
101
|
+
else:
|
|
102
|
+
#mark all AllExpressions as 'not exhausted' into the agenda since we are (potentially) adding new accessible vars
|
|
103
|
+
agenda.mark_alls_fresh();
|
|
104
|
+
return self._attempt_proof(agenda, accessible_vars|set(current.args), atoms|set([(current, False)]), debug+1)
|
|
105
|
+
|
|
106
|
+
def _attempt_proof_n_atom(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
107
|
+
# Check if the branch is closed. Return 'True' if it is
|
|
108
|
+
if (current.term, False) in atoms:
|
|
109
|
+
debug.line('CLOSED', 1)
|
|
110
|
+
return True
|
|
111
|
+
|
|
112
|
+
if context:
|
|
113
|
+
if isinstance(context.term, NegatedExpression):
|
|
114
|
+
current = current.negate()
|
|
115
|
+
agenda.put(context(current).simplify())
|
|
116
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
117
|
+
else:
|
|
118
|
+
#mark all AllExpressions as 'not exhausted' into the agenda since we are (potentially) adding new accessible vars
|
|
119
|
+
agenda.mark_alls_fresh();
|
|
120
|
+
return self._attempt_proof(agenda, accessible_vars|set(current.term.args), atoms|set([(current.term, True)]), debug+1)
|
|
121
|
+
|
|
122
|
+
def _attempt_proof_prop(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
123
|
+
# Check if the branch is closed. Return 'True' if it is
|
|
124
|
+
if (current, True) in atoms:
|
|
125
|
+
debug.line('CLOSED', 1)
|
|
126
|
+
return True
|
|
127
|
+
|
|
128
|
+
#mark all AllExpressions as 'not exhausted' into the agenda since we are (potentially) adding new accessible vars
|
|
129
|
+
agenda.mark_alls_fresh();
|
|
130
|
+
return self._attempt_proof(agenda, accessible_vars, atoms|set([(current, False)]), debug+1)
|
|
131
|
+
|
|
132
|
+
def _attempt_proof_n_prop(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
133
|
+
# Check if the branch is closed. Return 'True' if it is
|
|
134
|
+
if (current.term, False) in atoms:
|
|
135
|
+
debug.line('CLOSED', 1)
|
|
136
|
+
return True
|
|
137
|
+
|
|
138
|
+
#mark all AllExpressions as 'not exhausted' into the agenda since we are (potentially) adding new accessible vars
|
|
139
|
+
agenda.mark_alls_fresh();
|
|
140
|
+
return self._attempt_proof(agenda, accessible_vars, atoms|set([(current.term, True)]), debug+1)
|
|
141
|
+
|
|
142
|
+
def _attempt_proof_app(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
143
|
+
f, args = current.uncurry()
|
|
144
|
+
for i, arg in enumerate(args):
|
|
145
|
+
if not TableauProver.is_atom(arg):
|
|
146
|
+
ctx = f
|
|
147
|
+
nv = Variable('X%s' % _counter.get())
|
|
148
|
+
for j,a in enumerate(args):
|
|
149
|
+
ctx = (ctx(VariableExpression(nv)) if i == j else ctx(a))
|
|
150
|
+
if context:
|
|
151
|
+
ctx = context(ctx).simplify()
|
|
152
|
+
ctx = LambdaExpression(nv, ctx)
|
|
153
|
+
agenda.put(arg, ctx)
|
|
154
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
155
|
+
raise Exception('If this method is called, there must be a non-atomic argument')
|
|
156
|
+
|
|
157
|
+
def _attempt_proof_n_app(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
158
|
+
f, args = current.term.uncurry()
|
|
159
|
+
for i, arg in enumerate(args):
|
|
160
|
+
if not TableauProver.is_atom(arg):
|
|
161
|
+
ctx = f
|
|
162
|
+
nv = Variable('X%s' % _counter.get())
|
|
163
|
+
for j,a in enumerate(args):
|
|
164
|
+
ctx = (ctx(VariableExpression(nv)) if i == j else ctx(a))
|
|
165
|
+
if context:
|
|
166
|
+
#combine new context with existing
|
|
167
|
+
ctx = context(ctx).simplify()
|
|
168
|
+
ctx = LambdaExpression(nv, -ctx)
|
|
169
|
+
agenda.put(-arg, ctx)
|
|
170
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
171
|
+
raise Exception('If this method is called, there must be a non-atomic argument')
|
|
172
|
+
|
|
173
|
+
def _attempt_proof_n_eq(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
174
|
+
###########################################################################
|
|
175
|
+
# Since 'current' is of type '~(a=b)', the path is closed if 'a' == 'b'
|
|
176
|
+
###########################################################################
|
|
177
|
+
if current.term.first == current.term.second:
|
|
178
|
+
debug.line('CLOSED', 1)
|
|
179
|
+
return True
|
|
180
|
+
|
|
181
|
+
agenda[Categories.N_EQ].add((current,context))
|
|
182
|
+
current._exhausted = True
|
|
183
|
+
return self._attempt_proof(agenda, accessible_vars|set([current.term.first, current.term.second]), atoms, debug+1)
|
|
184
|
+
|
|
185
|
+
def _attempt_proof_d_neg(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
186
|
+
agenda.put(current.term.term, context)
|
|
187
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
188
|
+
|
|
189
|
+
def _attempt_proof_n_all(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
190
|
+
agenda[Categories.EXISTS].add((ExistsExpression(current.term.variable, -current.term.term), context))
|
|
191
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
192
|
+
|
|
193
|
+
def _attempt_proof_n_some(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
194
|
+
agenda[Categories.ALL].add((AllExpression(current.term.variable, -current.term.term), context))
|
|
195
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
196
|
+
|
|
197
|
+
def _attempt_proof_and(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
198
|
+
agenda.put(current.first, context)
|
|
199
|
+
agenda.put(current.second, context)
|
|
200
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
201
|
+
|
|
202
|
+
def _attempt_proof_n_or(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
203
|
+
agenda.put(-current.term.first, context)
|
|
204
|
+
agenda.put(-current.term.second, context)
|
|
205
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
206
|
+
|
|
207
|
+
def _attempt_proof_n_imp(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
208
|
+
agenda.put(current.term.first, context)
|
|
209
|
+
agenda.put(-current.term.second, context)
|
|
210
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
211
|
+
|
|
212
|
+
def _attempt_proof_or(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
213
|
+
new_agenda = agenda.clone()
|
|
214
|
+
agenda.put(current.first, context)
|
|
215
|
+
new_agenda.put(current.second, context)
|
|
216
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1) and \
|
|
217
|
+
self._attempt_proof(new_agenda, accessible_vars, atoms, debug+1)
|
|
218
|
+
|
|
219
|
+
def _attempt_proof_imp(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
220
|
+
new_agenda = agenda.clone()
|
|
221
|
+
agenda.put(-current.first, context)
|
|
222
|
+
new_agenda.put(current.second, context)
|
|
223
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1) and \
|
|
224
|
+
self._attempt_proof(new_agenda, accessible_vars, atoms, debug+1)
|
|
225
|
+
|
|
226
|
+
def _attempt_proof_n_and(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
227
|
+
new_agenda = agenda.clone()
|
|
228
|
+
agenda.put(-current.term.first, context)
|
|
229
|
+
new_agenda.put(-current.term.second, context)
|
|
230
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1) and \
|
|
231
|
+
self._attempt_proof(new_agenda, accessible_vars, atoms, debug+1)
|
|
232
|
+
|
|
233
|
+
def _attempt_proof_iff(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
234
|
+
new_agenda = agenda.clone()
|
|
235
|
+
agenda.put(current.first, context)
|
|
236
|
+
agenda.put(current.second, context)
|
|
237
|
+
new_agenda.put(-current.first, context)
|
|
238
|
+
new_agenda.put(-current.second, context)
|
|
239
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1) and \
|
|
240
|
+
self._attempt_proof(new_agenda, accessible_vars, atoms, debug+1)
|
|
241
|
+
|
|
242
|
+
def _attempt_proof_n_iff(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
243
|
+
new_agenda = agenda.clone()
|
|
244
|
+
agenda.put(current.term.first, context)
|
|
245
|
+
agenda.put(-current.term.second, context)
|
|
246
|
+
new_agenda.put(-current.term.first, context)
|
|
247
|
+
new_agenda.put(current.term.second, context)
|
|
248
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1) and \
|
|
249
|
+
self._attempt_proof(new_agenda, accessible_vars, atoms, debug+1)
|
|
250
|
+
|
|
251
|
+
def _attempt_proof_eq(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
252
|
+
#########################################################################
|
|
253
|
+
# Since 'current' is of the form '(a = b)', replace ALL free instances
|
|
254
|
+
# of 'a' with 'b'
|
|
255
|
+
#########################################################################
|
|
256
|
+
agenda.put_atoms(atoms)
|
|
257
|
+
agenda.replace_all(current.first, current.second)
|
|
258
|
+
accessible_vars.discard(current.first)
|
|
259
|
+
agenda.mark_neqs_fresh();
|
|
260
|
+
return self._attempt_proof(agenda, accessible_vars, set(), debug+1)
|
|
261
|
+
|
|
262
|
+
def _attempt_proof_some(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
263
|
+
new_unique_variable = VariableExpression(unique_variable())
|
|
264
|
+
agenda.put(current.term.replace(current.variable, new_unique_variable), context)
|
|
265
|
+
agenda.mark_alls_fresh()
|
|
266
|
+
return self._attempt_proof(agenda, accessible_vars|set([new_unique_variable]), atoms, debug+1)
|
|
267
|
+
|
|
268
|
+
def _attempt_proof_all(self, current, context, agenda, accessible_vars, atoms, debug):
|
|
269
|
+
try:
|
|
270
|
+
current._used_vars
|
|
271
|
+
except AttributeError:
|
|
272
|
+
current._used_vars = set()
|
|
273
|
+
|
|
274
|
+
#if there are accessible_vars on the path
|
|
275
|
+
if accessible_vars:
|
|
276
|
+
# get the set of bound variables that have not be used by this AllExpression
|
|
277
|
+
bv_available = accessible_vars - current._used_vars
|
|
278
|
+
|
|
279
|
+
if bv_available:
|
|
280
|
+
variable_to_use = list(bv_available)[0]
|
|
281
|
+
debug.line('--> Using \'%s\'' % variable_to_use, 2)
|
|
282
|
+
current._used_vars |= set([variable_to_use])
|
|
283
|
+
agenda.put(current.term.replace(current.variable, variable_to_use), context)
|
|
284
|
+
agenda[Categories.ALL].add((current,context))
|
|
285
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
286
|
+
|
|
287
|
+
else:
|
|
288
|
+
#no more available variables to substitute
|
|
289
|
+
debug.line('--> Variables Exhausted', 2)
|
|
290
|
+
current._exhausted = True
|
|
291
|
+
agenda[Categories.ALL].add((current,context))
|
|
292
|
+
return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
|
|
293
|
+
|
|
294
|
+
else:
|
|
295
|
+
new_unique_variable = VariableExpression(unique_variable())
|
|
296
|
+
debug.line('--> Using \'%s\'' % new_unique_variable, 2)
|
|
297
|
+
current._used_vars |= set([new_unique_variable])
|
|
298
|
+
agenda.put(current.term.replace(current.variable, new_unique_variable), context)
|
|
299
|
+
agenda[Categories.ALL].add((current,context))
|
|
300
|
+
agenda.mark_alls_fresh()
|
|
301
|
+
return self._attempt_proof(agenda, accessible_vars|set([new_unique_variable]), atoms, debug+1)
|
|
302
|
+
|
|
303
|
+
@staticmethod
|
|
304
|
+
def is_atom(e):
|
|
305
|
+
if isinstance(e, NegatedExpression):
|
|
306
|
+
e = e.term
|
|
307
|
+
|
|
308
|
+
if isinstance(e, ApplicationExpression):
|
|
309
|
+
for arg in e.args:
|
|
310
|
+
if not TableauProver.is_atom(arg):
|
|
311
|
+
return False
|
|
312
|
+
return True
|
|
313
|
+
elif isinstance(e, AbstractVariableExpression) or \
|
|
314
|
+
isinstance(e, LambdaExpression):
|
|
315
|
+
return True
|
|
316
|
+
else:
|
|
317
|
+
return False
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
class TableauProverCommand(BaseProverCommand):
|
|
321
|
+
def __init__(self, goal=None, assumptions=None, prover=None):
|
|
322
|
+
"""
|
|
323
|
+
:param goal: Input expression to prove
|
|
324
|
+
:type goal: sem.Expression
|
|
325
|
+
:param assumptions: Input expressions to use as assumptions in
|
|
326
|
+
the proof.
|
|
327
|
+
:type assumptions: list(sem.Expression)
|
|
328
|
+
"""
|
|
329
|
+
if prover is not None:
|
|
330
|
+
assert isinstance(prover, TableauProver)
|
|
331
|
+
else:
|
|
332
|
+
prover = TableauProver()
|
|
333
|
+
|
|
334
|
+
BaseProverCommand.__init__(self, prover, goal, assumptions)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
class Agenda(object):
|
|
338
|
+
def __init__(self):
|
|
339
|
+
self.sets = tuple(set() for i in range(21))
|
|
340
|
+
|
|
341
|
+
def clone(self):
|
|
342
|
+
new_agenda = Agenda()
|
|
343
|
+
set_list = [s.copy() for s in self.sets]
|
|
344
|
+
|
|
345
|
+
new_allExs = set()
|
|
346
|
+
for allEx,_ in set_list[Categories.ALL]:
|
|
347
|
+
new_allEx = AllExpression(allEx.variable, allEx.term)
|
|
348
|
+
try:
|
|
349
|
+
new_allEx._used_vars = set(used for used in allEx._used_vars)
|
|
350
|
+
except AttributeError:
|
|
351
|
+
new_allEx._used_vars = set()
|
|
352
|
+
new_allExs.add((new_allEx,None))
|
|
353
|
+
set_list[Categories.ALL] = new_allExs
|
|
354
|
+
|
|
355
|
+
set_list[Categories.N_EQ] = set((NegatedExpression(n_eq.term),ctx)
|
|
356
|
+
for (n_eq,ctx) in set_list[Categories.N_EQ])
|
|
357
|
+
|
|
358
|
+
new_agenda.sets = tuple(set_list)
|
|
359
|
+
return new_agenda
|
|
360
|
+
|
|
361
|
+
def __getitem__(self, index):
|
|
362
|
+
return self.sets[index]
|
|
363
|
+
|
|
364
|
+
def put(self, expression, context=None):
|
|
365
|
+
if isinstance(expression, AllExpression):
|
|
366
|
+
ex_to_add = AllExpression(expression.variable, expression.term)
|
|
367
|
+
try:
|
|
368
|
+
ex_to_add._used_vars = set(used for used in expression._used_vars)
|
|
369
|
+
except AttributeError:
|
|
370
|
+
ex_to_add._used_vars = set()
|
|
371
|
+
else:
|
|
372
|
+
ex_to_add = expression
|
|
373
|
+
self.sets[self._categorize_expression(ex_to_add)].add((ex_to_add, context))
|
|
374
|
+
|
|
375
|
+
def put_all(self, expressions):
|
|
376
|
+
for expression in expressions:
|
|
377
|
+
self.put(expression)
|
|
378
|
+
|
|
379
|
+
def put_atoms(self, atoms):
|
|
380
|
+
for atom, neg in atoms:
|
|
381
|
+
if neg:
|
|
382
|
+
self[Categories.N_ATOM].add((-atom,None))
|
|
383
|
+
else:
|
|
384
|
+
self[Categories.ATOM].add((atom,None))
|
|
385
|
+
|
|
386
|
+
def pop_first(self):
|
|
387
|
+
""" Pop the first expression that appears in the agenda """
|
|
388
|
+
for i,s in enumerate(self.sets):
|
|
389
|
+
if s:
|
|
390
|
+
if i in [Categories.N_EQ, Categories.ALL]:
|
|
391
|
+
for ex in s:
|
|
392
|
+
try:
|
|
393
|
+
if not ex[0]._exhausted:
|
|
394
|
+
s.remove(ex)
|
|
395
|
+
return (ex, i)
|
|
396
|
+
except AttributeError:
|
|
397
|
+
s.remove(ex)
|
|
398
|
+
return (ex, i)
|
|
399
|
+
else:
|
|
400
|
+
return (s.pop(), i)
|
|
401
|
+
return ((None, None), None)
|
|
402
|
+
|
|
403
|
+
def replace_all(self, old, new):
|
|
404
|
+
for s in self.sets:
|
|
405
|
+
for ex,ctx in s:
|
|
406
|
+
ex.replace(old.variable, new)
|
|
407
|
+
if ctx is not None:
|
|
408
|
+
ctx.replace(old.variable, new)
|
|
409
|
+
|
|
410
|
+
def mark_alls_fresh(self):
|
|
411
|
+
for u,_ in self.sets[Categories.ALL]:
|
|
412
|
+
u._exhausted = False
|
|
413
|
+
|
|
414
|
+
def mark_neqs_fresh(self):
|
|
415
|
+
for neq,_ in self.sets[Categories.N_EQ]:
|
|
416
|
+
neq._exhausted = False
|
|
417
|
+
|
|
418
|
+
def _categorize_expression(self, current):
|
|
419
|
+
if isinstance(current, NegatedExpression):
|
|
420
|
+
return self._categorize_NegatedExpression(current)
|
|
421
|
+
elif isinstance(current, FunctionVariableExpression):
|
|
422
|
+
return Categories.PROP
|
|
423
|
+
elif TableauProver.is_atom(current):
|
|
424
|
+
return Categories.ATOM
|
|
425
|
+
elif isinstance(current, AllExpression):
|
|
426
|
+
return Categories.ALL
|
|
427
|
+
elif isinstance(current, AndExpression):
|
|
428
|
+
return Categories.AND
|
|
429
|
+
elif isinstance(current, OrExpression):
|
|
430
|
+
return Categories.OR
|
|
431
|
+
elif isinstance(current, ImpExpression):
|
|
432
|
+
return Categories.IMP
|
|
433
|
+
elif isinstance(current, IffExpression):
|
|
434
|
+
return Categories.IFF
|
|
435
|
+
elif isinstance(current, EqualityExpression):
|
|
436
|
+
return Categories.EQ
|
|
437
|
+
elif isinstance(current, ExistsExpression):
|
|
438
|
+
return Categories.EXISTS
|
|
439
|
+
elif isinstance(current, ApplicationExpression):
|
|
440
|
+
return Categories.APP
|
|
441
|
+
else:
|
|
442
|
+
raise ProverParseError("cannot categorize %s" % \
|
|
443
|
+
current.__class__.__name__)
|
|
444
|
+
|
|
445
|
+
def _categorize_NegatedExpression(self, current):
|
|
446
|
+
negated = current.term
|
|
447
|
+
|
|
448
|
+
if isinstance(negated, NegatedExpression):
|
|
449
|
+
return Categories.D_NEG
|
|
450
|
+
elif isinstance(negated, FunctionVariableExpression):
|
|
451
|
+
return Categories.N_PROP
|
|
452
|
+
elif TableauProver.is_atom(negated):
|
|
453
|
+
return Categories.N_ATOM
|
|
454
|
+
elif isinstance(negated, AllExpression):
|
|
455
|
+
return Categories.N_ALL
|
|
456
|
+
elif isinstance(negated, AndExpression):
|
|
457
|
+
return Categories.N_AND
|
|
458
|
+
elif isinstance(negated, OrExpression):
|
|
459
|
+
return Categories.N_OR
|
|
460
|
+
elif isinstance(negated, ImpExpression):
|
|
461
|
+
return Categories.N_IMP
|
|
462
|
+
elif isinstance(negated, IffExpression):
|
|
463
|
+
return Categories.N_IFF
|
|
464
|
+
elif isinstance(negated, EqualityExpression):
|
|
465
|
+
return Categories.N_EQ
|
|
466
|
+
elif isinstance(negated, ExistsExpression):
|
|
467
|
+
return Categories.N_EXISTS
|
|
468
|
+
elif isinstance(negated, ApplicationExpression):
|
|
469
|
+
return Categories.N_APP
|
|
470
|
+
else:
|
|
471
|
+
raise ProverParseError("cannot categorize %s" % \
|
|
472
|
+
negated.__class__.__name__)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
class Debug(object):
|
|
476
|
+
def __init__(self, verbose, indent=0, lines=None):
|
|
477
|
+
self.verbose = verbose
|
|
478
|
+
self.indent = indent
|
|
479
|
+
|
|
480
|
+
if not lines: lines = []
|
|
481
|
+
self.lines = lines
|
|
482
|
+
|
|
483
|
+
def __add__(self, increment):
|
|
484
|
+
return Debug(self.verbose, self.indent+1, self.lines)
|
|
485
|
+
|
|
486
|
+
def line(self, data, indent=0):
|
|
487
|
+
if isinstance(data, tuple):
|
|
488
|
+
ex, ctx = data
|
|
489
|
+
if ctx:
|
|
490
|
+
data = '%s, %s' % (ex, ctx)
|
|
491
|
+
else:
|
|
492
|
+
data = '%s' % ex
|
|
493
|
+
|
|
494
|
+
if isinstance(ex, AllExpression):
|
|
495
|
+
try:
|
|
496
|
+
used_vars = "[%s]" % (",".join("%s" % ve.variable.name for ve in ex._used_vars))
|
|
497
|
+
data += ': %s' % used_vars
|
|
498
|
+
except AttributeError:
|
|
499
|
+
data += ': []'
|
|
500
|
+
|
|
501
|
+
newline = '%s%s' % (' '*(self.indent+indent), data)
|
|
502
|
+
self.lines.append(newline)
|
|
503
|
+
|
|
504
|
+
if self.verbose:
|
|
505
|
+
print(newline)
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
class Categories(object):
|
|
509
|
+
ATOM = 0
|
|
510
|
+
PROP = 1
|
|
511
|
+
N_ATOM = 2
|
|
512
|
+
N_PROP = 3
|
|
513
|
+
APP = 4
|
|
514
|
+
N_APP = 5
|
|
515
|
+
N_EQ = 6
|
|
516
|
+
D_NEG = 7
|
|
517
|
+
N_ALL = 8
|
|
518
|
+
N_EXISTS = 9
|
|
519
|
+
AND = 10
|
|
520
|
+
N_OR = 11
|
|
521
|
+
N_IMP = 12
|
|
522
|
+
OR = 13
|
|
523
|
+
IMP = 14
|
|
524
|
+
N_AND = 15
|
|
525
|
+
IFF = 16
|
|
526
|
+
N_IFF = 17
|
|
527
|
+
EQ = 18
|
|
528
|
+
EXISTS = 19
|
|
529
|
+
ALL = 20
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
def testTableauProver():
|
|
533
|
+
tableau_test('P | -P')
|
|
534
|
+
tableau_test('P & -P')
|
|
535
|
+
tableau_test('Q', ['P', '(P -> Q)'])
|
|
536
|
+
tableau_test('man(x)')
|
|
537
|
+
tableau_test('(man(x) -> man(x))')
|
|
538
|
+
tableau_test('(man(x) -> --man(x))')
|
|
539
|
+
tableau_test('-(man(x) and -man(x))')
|
|
540
|
+
tableau_test('(man(x) or -man(x))')
|
|
541
|
+
tableau_test('(man(x) -> man(x))')
|
|
542
|
+
tableau_test('-(man(x) and -man(x))')
|
|
543
|
+
tableau_test('(man(x) or -man(x))')
|
|
544
|
+
tableau_test('(man(x) -> man(x))')
|
|
545
|
+
tableau_test('(man(x) iff man(x))')
|
|
546
|
+
tableau_test('-(man(x) iff -man(x))')
|
|
547
|
+
tableau_test('all x.man(x)')
|
|
548
|
+
tableau_test('all x.all y.((x = y) -> (y = x))')
|
|
549
|
+
tableau_test('all x.all y.all z.(((x = y) & (y = z)) -> (x = z))')
|
|
550
|
+
# tableau_test('-all x.some y.F(x,y) & some x.all y.(-F(x,y))')
|
|
551
|
+
# tableau_test('some x.all y.sees(x,y)')
|
|
552
|
+
|
|
553
|
+
p1 = 'all x.(man(x) -> mortal(x))'
|
|
554
|
+
p2 = 'man(Socrates)'
|
|
555
|
+
c = 'mortal(Socrates)'
|
|
556
|
+
tableau_test(c, [p1, p2])
|
|
557
|
+
|
|
558
|
+
p1 = 'all x.(man(x) -> walks(x))'
|
|
559
|
+
p2 = 'man(John)'
|
|
560
|
+
c = 'some y.walks(y)'
|
|
561
|
+
tableau_test(c, [p1, p2])
|
|
562
|
+
|
|
563
|
+
p = '((x = y) & walks(y))'
|
|
564
|
+
c = 'walks(x)'
|
|
565
|
+
tableau_test(c, [p])
|
|
566
|
+
|
|
567
|
+
p = '((x = y) & ((y = z) & (z = w)))'
|
|
568
|
+
c = '(x = w)'
|
|
569
|
+
tableau_test(c, [p])
|
|
570
|
+
|
|
571
|
+
p = 'some e1.some e2.(believe(e1,john,e2) & walk(e2,mary))'
|
|
572
|
+
c = 'some e0.walk(e0,mary)'
|
|
573
|
+
tableau_test(c, [p])
|
|
574
|
+
|
|
575
|
+
c = '(exists x.exists z3.((x = Mary) & ((z3 = John) & sees(z3,x))) <-> exists x.exists z4.((x = John) & ((z4 = Mary) & sees(x,z4))))'
|
|
576
|
+
tableau_test(c)
|
|
577
|
+
|
|
578
|
+
# p = 'some e1.some e2.((believe e1 john e2) and (walk e2 mary))'
|
|
579
|
+
# c = 'some x.some e3.some e4.((believe e3 x e4) and (walk e4 mary))'
|
|
580
|
+
# tableau_test(c, [p])
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
def testHigherOrderTableauProver():
|
|
584
|
+
tableau_test('believe(j, -lie(b))', ['believe(j, -lie(b) & -cheat(b))'])
|
|
585
|
+
tableau_test('believe(j, lie(b) & cheat(b))', ['believe(j, lie(b))'])
|
|
586
|
+
tableau_test('believe(j, lie(b))', ['lie(b)']) #how do we capture that John believes all things that are true
|
|
587
|
+
tableau_test('believe(j, know(b, cheat(b)))', ['believe(j, know(b, lie(b)) & know(b, steals(b) & cheat(b)))'])
|
|
588
|
+
tableau_test('P(Q(y), R(y) & R(z))', ['P(Q(x) & Q(y), R(y) & R(z))'])
|
|
589
|
+
|
|
590
|
+
tableau_test('believe(j, cheat(b) & lie(b))', ['believe(j, lie(b) & cheat(b))'])
|
|
591
|
+
tableau_test('believe(j, -cheat(b) & -lie(b))', ['believe(j, -lie(b) & -cheat(b))'])
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
def tableau_test(c, ps=None, verbose=False):
|
|
595
|
+
pc = Expression.fromstring(c)
|
|
596
|
+
pps = ([Expression.fromstring(p) for p in ps] if ps else [])
|
|
597
|
+
if not ps:
|
|
598
|
+
ps = []
|
|
599
|
+
print('%s |- %s: %s' % (', '.join(ps), pc, TableauProver().prove(pc, pps, verbose=verbose)))
|
|
600
|
+
|
|
601
|
+
def demo():
|
|
602
|
+
testTableauProver()
|
|
603
|
+
testHigherOrderTableauProver()
|
|
604
|
+
|
|
605
|
+
if __name__ == '__main__':
|
|
606
|
+
demo()
|
|
607
|
+
|