logic.doctest 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098
  1. .. Copyright (C) 2001-2020 NLTK Project
  2. .. For license information, see LICENSE.TXT
  3. =======================
  4. Logic & Lambda Calculus
  5. =======================
  6. The `nltk.logic` package allows expressions of First-Order Logic (FOL) to be
  7. parsed into ``Expression`` objects. In addition to FOL, the parser
  8. handles lambda-abstraction with variables of higher order.
  9. --------
  10. Overview
  11. --------
  12. >>> from nltk.sem.logic import *
  13. The default inventory of logical constants is the following:
  14. >>> boolean_ops() # doctest: +NORMALIZE_WHITESPACE
  15. negation -
  16. conjunction &
  17. disjunction |
  18. implication ->
  19. equivalence <->
  20. >>> equality_preds() # doctest: +NORMALIZE_WHITESPACE
  21. equality =
  22. inequality !=
  23. >>> binding_ops() # doctest: +NORMALIZE_WHITESPACE
  24. existential exists
  25. universal all
  26. lambda \
  27. ----------------
  28. Regression Tests
  29. ----------------
  30. Untyped Logic
  31. +++++++++++++
  32. Process logical expressions conveniently:
  33. >>> read_expr = Expression.fromstring
  34. Test for equality under alpha-conversion
  35. ========================================
  36. >>> e1 = read_expr('exists x.P(x)')
  37. >>> print(e1)
  38. exists x.P(x)
  39. >>> e2 = e1.alpha_convert(Variable('z'))
  40. >>> print(e2)
  41. exists z.P(z)
  42. >>> e1 == e2
  43. True
  44. >>> l = read_expr(r'\X.\X.X(X)(1)').simplify()
  45. >>> id = read_expr(r'\X.X(X)')
  46. >>> l == id
  47. True
  48. Test numerals
  49. =============
  50. >>> zero = read_expr(r'\F x.x')
  51. >>> one = read_expr(r'\F x.F(x)')
  52. >>> two = read_expr(r'\F x.F(F(x))')
  53. >>> three = read_expr(r'\F x.F(F(F(x)))')
  54. >>> four = read_expr(r'\F x.F(F(F(F(x))))')
  55. >>> succ = read_expr(r'\N F x.F(N(F,x))')
  56. >>> plus = read_expr(r'\M N F x.M(F,N(F,x))')
  57. >>> mult = read_expr(r'\M N F.M(N(F))')
  58. >>> pred = read_expr(r'\N F x.(N(\G H.H(G(F)))(\u.x)(\u.u))')
  59. >>> v1 = ApplicationExpression(succ, zero).simplify()
  60. >>> v1 == one
  61. True
  62. >>> v2 = ApplicationExpression(succ, v1).simplify()
  63. >>> v2 == two
  64. True
  65. >>> v3 = ApplicationExpression(ApplicationExpression(plus, v1), v2).simplify()
  66. >>> v3 == three
  67. True
  68. >>> v4 = ApplicationExpression(ApplicationExpression(mult, v2), v2).simplify()
  69. >>> v4 == four
  70. True
  71. >>> v5 = ApplicationExpression(pred, ApplicationExpression(pred, v4)).simplify()
  72. >>> v5 == two
  73. True
  74. Overloaded operators also exist, for convenience.
  75. >>> print(succ(zero).simplify() == one)
  76. True
  77. >>> print(plus(one,two).simplify() == three)
  78. True
  79. >>> print(mult(two,two).simplify() == four)
  80. True
  81. >>> print(pred(pred(four)).simplify() == two)
  82. True
  83. >>> john = read_expr(r'john')
  84. >>> man = read_expr(r'\x.man(x)')
  85. >>> walk = read_expr(r'\x.walk(x)')
  86. >>> man(john).simplify()
  87. <ApplicationExpression man(john)>
  88. >>> print(-walk(john).simplify())
  89. -walk(john)
  90. >>> print((man(john) & walk(john)).simplify())
  91. (man(john) & walk(john))
  92. >>> print((man(john) | walk(john)).simplify())
  93. (man(john) | walk(john))
  94. >>> print((man(john) > walk(john)).simplify())
  95. (man(john) -> walk(john))
  96. >>> print((man(john) < walk(john)).simplify())
  97. (man(john) <-> walk(john))
  98. Python's built-in lambda operator can also be used with Expressions
  99. >>> john = VariableExpression(Variable('john'))
  100. >>> run_var = VariableExpression(Variable('run'))
  101. >>> run = lambda x: run_var(x)
  102. >>> run(john)
  103. <ApplicationExpression run(john)>
  104. ``betaConversionTestSuite.pl``
  105. ------------------------------
  106. Tests based on Blackburn & Bos' book, *Representation and Inference
  107. for Natural Language*.
  108. >>> x1 = read_expr(r'\P.P(mia)(\x.walk(x))').simplify()
  109. >>> x2 = read_expr(r'walk(mia)').simplify()
  110. >>> x1 == x2
  111. True
  112. >>> x1 = read_expr(r'exists x.(man(x) & ((\P.exists x.(woman(x) & P(x)))(\y.love(x,y))))').simplify()
  113. >>> x2 = read_expr(r'exists x.(man(x) & exists y.(woman(y) & love(x,y)))').simplify()
  114. >>> x1 == x2
  115. True
  116. >>> x1 = read_expr(r'\a.sleep(a)(mia)').simplify()
  117. >>> x2 = read_expr(r'sleep(mia)').simplify()
  118. >>> x1 == x2
  119. True
  120. >>> x1 = read_expr(r'\a.\b.like(b,a)(mia)').simplify()
  121. >>> x2 = read_expr(r'\b.like(b,mia)').simplify()
  122. >>> x1 == x2
  123. True
  124. >>> x1 = read_expr(r'\a.(\b.like(b,a)(vincent))').simplify()
  125. >>> x2 = read_expr(r'\a.like(vincent,a)').simplify()
  126. >>> x1 == x2
  127. True
  128. >>> x1 = read_expr(r'\a.((\b.like(b,a)(vincent)) & sleep(a))').simplify()
  129. >>> x2 = read_expr(r'\a.(like(vincent,a) & sleep(a))').simplify()
  130. >>> x1 == x2
  131. True
  132. >>> x1 = read_expr(r'(\a.\b.like(b,a)(mia)(vincent))').simplify()
  133. >>> x2 = read_expr(r'like(vincent,mia)').simplify()
  134. >>> x1 == x2
  135. True
  136. >>> x1 = read_expr(r'P((\a.sleep(a)(vincent)))').simplify()
  137. >>> x2 = read_expr(r'P(sleep(vincent))').simplify()
  138. >>> x1 == x2
  139. True
  140. >>> x1 = read_expr(r'\A.A((\b.sleep(b)(vincent)))').simplify()
  141. >>> x2 = read_expr(r'\A.A(sleep(vincent))').simplify()
  142. >>> x1 == x2
  143. True
  144. >>> x1 = read_expr(r'\A.A(sleep(vincent))').simplify()
  145. >>> x2 = read_expr(r'\A.A(sleep(vincent))').simplify()
  146. >>> x1 == x2
  147. True
  148. >>> x1 = read_expr(r'(\A.A(vincent)(\b.sleep(b)))').simplify()
  149. >>> x2 = read_expr(r'sleep(vincent)').simplify()
  150. >>> x1 == x2
  151. True
  152. >>> x1 = read_expr(r'\A.believe(mia,A(vincent))(\b.sleep(b))').simplify()
  153. >>> x2 = read_expr(r'believe(mia,sleep(vincent))').simplify()
  154. >>> x1 == x2
  155. True
  156. >>> x1 = read_expr(r'(\A.(A(vincent) & A(mia)))(\b.sleep(b))').simplify()
  157. >>> x2 = read_expr(r'(sleep(vincent) & sleep(mia))').simplify()
  158. >>> x1 == x2
  159. True
  160. >>> x1 = read_expr(r'\A.\B.(\C.C(A(vincent))(\d.probably(d)) & (\C.C(B(mia))(\d.improbably(d))))(\f.walk(f))(\f.talk(f))').simplify()
  161. >>> x2 = read_expr(r'(probably(walk(vincent)) & improbably(talk(mia)))').simplify()
  162. >>> x1 == x2
  163. True
  164. >>> x1 = read_expr(r'(\a.\b.(\C.C(a,b)(\d.\f.love(d,f))))(jules)(mia)').simplify()
  165. >>> x2 = read_expr(r'love(jules,mia)').simplify()
  166. >>> x1 == x2
  167. True
  168. >>> x1 = read_expr(r'(\A.\B.exists c.(A(c) & B(c)))(\d.boxer(d),\d.sleep(d))').simplify()
  169. >>> x2 = read_expr(r'exists c.(boxer(c) & sleep(c))').simplify()
  170. >>> x1 == x2
  171. True
  172. >>> x1 = read_expr(r'\A.Z(A)(\c.\a.like(a,c))').simplify()
  173. >>> x2 = read_expr(r'Z(\c.\a.like(a,c))').simplify()
  174. >>> x1 == x2
  175. True
  176. >>> x1 = read_expr(r'\A.\b.A(b)(\c.\b.like(b,c))').simplify()
  177. >>> x2 = read_expr(r'\b.(\c.\b.like(b,c)(b))').simplify()
  178. >>> x1 == x2
  179. True
  180. >>> x1 = read_expr(r'(\a.\b.(\C.C(a,b)(\b.\a.loves(b,a))))(jules)(mia)').simplify()
  181. >>> x2 = read_expr(r'loves(jules,mia)').simplify()
  182. >>> x1 == x2
  183. True
  184. >>> x1 = read_expr(r'(\A.\b.(exists b.A(b) & A(b)))(\c.boxer(c))(vincent)').simplify()
  185. >>> x2 = read_expr(r'((exists b.boxer(b)) & boxer(vincent))').simplify()
  186. >>> x1 == x2
  187. True
  188. Test Parser
  189. ===========
  190. >>> print(read_expr(r'john'))
  191. john
  192. >>> print(read_expr(r'x'))
  193. x
  194. >>> print(read_expr(r'-man(x)'))
  195. -man(x)
  196. >>> print(read_expr(r'--man(x)'))
  197. --man(x)
  198. >>> print(read_expr(r'(man(x))'))
  199. man(x)
  200. >>> print(read_expr(r'((man(x)))'))
  201. man(x)
  202. >>> print(read_expr(r'man(x) <-> tall(x)'))
  203. (man(x) <-> tall(x))
  204. >>> print(read_expr(r'(man(x) <-> tall(x))'))
  205. (man(x) <-> tall(x))
  206. >>> print(read_expr(r'(man(x) & tall(x) & walks(x))'))
  207. (man(x) & tall(x) & walks(x))
  208. >>> print(read_expr(r'(man(x) & tall(x) & walks(x))').first)
  209. (man(x) & tall(x))
  210. >>> print(read_expr(r'man(x) | tall(x) & walks(x)'))
  211. (man(x) | (tall(x) & walks(x)))
  212. >>> print(read_expr(r'((man(x) & tall(x)) | walks(x))'))
  213. ((man(x) & tall(x)) | walks(x))
  214. >>> print(read_expr(r'man(x) & (tall(x) | walks(x))'))
  215. (man(x) & (tall(x) | walks(x)))
  216. >>> print(read_expr(r'(man(x) & (tall(x) | walks(x)))'))
  217. (man(x) & (tall(x) | walks(x)))
  218. >>> print(read_expr(r'P(x) -> Q(x) <-> R(x) | S(x) & T(x)'))
  219. ((P(x) -> Q(x)) <-> (R(x) | (S(x) & T(x))))
  220. >>> print(read_expr(r'exists x.man(x)'))
  221. exists x.man(x)
  222. >>> print(read_expr(r'exists x.(man(x) & tall(x))'))
  223. exists x.(man(x) & tall(x))
  224. >>> print(read_expr(r'exists x.(man(x) & tall(x) & walks(x))'))
  225. exists x.(man(x) & tall(x) & walks(x))
  226. >>> print(read_expr(r'-P(x) & Q(x)'))
  227. (-P(x) & Q(x))
  228. >>> read_expr(r'-P(x) & Q(x)') == read_expr(r'(-P(x)) & Q(x)')
  229. True
  230. >>> print(read_expr(r'\x.man(x)'))
  231. \x.man(x)
  232. >>> print(read_expr(r'\x.man(x)(john)'))
  233. \x.man(x)(john)
  234. >>> print(read_expr(r'\x.man(x)(john) & tall(x)'))
  235. (\x.man(x)(john) & tall(x))
  236. >>> print(read_expr(r'\x.\y.sees(x,y)'))
  237. \x y.sees(x,y)
  238. >>> print(read_expr(r'\x y.sees(x,y)'))
  239. \x y.sees(x,y)
  240. >>> print(read_expr(r'\x.\y.sees(x,y)(a)'))
  241. (\x y.sees(x,y))(a)
  242. >>> print(read_expr(r'\x y.sees(x,y)(a)'))
  243. (\x y.sees(x,y))(a)
  244. >>> print(read_expr(r'\x.\y.sees(x,y)(a)(b)'))
  245. ((\x y.sees(x,y))(a))(b)
  246. >>> print(read_expr(r'\x y.sees(x,y)(a)(b)'))
  247. ((\x y.sees(x,y))(a))(b)
  248. >>> print(read_expr(r'\x.\y.sees(x,y)(a,b)'))
  249. ((\x y.sees(x,y))(a))(b)
  250. >>> print(read_expr(r'\x y.sees(x,y)(a,b)'))
  251. ((\x y.sees(x,y))(a))(b)
  252. >>> print(read_expr(r'((\x.\y.sees(x,y))(a))(b)'))
  253. ((\x y.sees(x,y))(a))(b)
  254. >>> print(read_expr(r'P(x)(y)(z)'))
  255. P(x,y,z)
  256. >>> print(read_expr(r'P(Q)'))
  257. P(Q)
  258. >>> print(read_expr(r'P(Q(x))'))
  259. P(Q(x))
  260. >>> print(read_expr(r'(\x.exists y.walks(x,y))(x)'))
  261. (\x.exists y.walks(x,y))(x)
  262. >>> print(read_expr(r'exists x.(x = john)'))
  263. exists x.(x = john)
  264. >>> print(read_expr(r'((\P.\Q.exists x.(P(x) & Q(x)))(\x.dog(x)))(\x.bark(x))'))
  265. ((\P Q.exists x.(P(x) & Q(x)))(\x.dog(x)))(\x.bark(x))
  266. >>> a = read_expr(r'exists c.exists b.A(b,c) & A(b,c)')
  267. >>> b = read_expr(r'(exists c.(exists b.A(b,c))) & A(b,c)')
  268. >>> print(a == b)
  269. True
  270. >>> a = read_expr(r'exists c.(exists b.A(b,c) & A(b,c))')
  271. >>> b = read_expr(r'exists c.((exists b.A(b,c)) & A(b,c))')
  272. >>> print(a == b)
  273. True
  274. >>> print(read_expr(r'exists x.x = y'))
  275. exists x.(x = y)
  276. >>> print(read_expr('A(B)(C)'))
  277. A(B,C)
  278. >>> print(read_expr('(A(B))(C)'))
  279. A(B,C)
  280. >>> print(read_expr('A((B)(C))'))
  281. A(B(C))
  282. >>> print(read_expr('A(B(C))'))
  283. A(B(C))
  284. >>> print(read_expr('(A)(B(C))'))
  285. A(B(C))
  286. >>> print(read_expr('(((A)))(((B))(((C))))'))
  287. A(B(C))
  288. >>> print(read_expr(r'A != B'))
  289. -(A = B)
  290. >>> print(read_expr('P(x) & x=y & P(y)'))
  291. (P(x) & (x = y) & P(y))
  292. >>> try: print(read_expr(r'\walk.walk(x)'))
  293. ... except LogicalExpressionException as e: print(e)
  294. 'walk' is an illegal variable name. Constants may not be abstracted.
  295. \walk.walk(x)
  296. ^
  297. >>> try: print(read_expr(r'all walk.walk(john)'))
  298. ... except LogicalExpressionException as e: print(e)
  299. 'walk' is an illegal variable name. Constants may not be quantified.
  300. all walk.walk(john)
  301. ^
  302. >>> try: print(read_expr(r'x(john)'))
  303. ... except LogicalExpressionException as e: print(e)
  304. 'x' is an illegal predicate name. Individual variables may not be used as predicates.
  305. x(john)
  306. ^
  307. >>> from nltk.sem.logic import LogicParser # hack to give access to custom quote chars
  308. >>> lpq = LogicParser()
  309. >>> lpq.quote_chars = [("'", "'", "\\", False)]
  310. >>> print(lpq.parse(r"(man(x) & 'tall\'s,' (x) & walks (x) )"))
  311. (man(x) & tall's,(x) & walks(x))
  312. >>> lpq.quote_chars = [("'", "'", "\\", True)]
  313. >>> print(lpq.parse(r"'tall\'s,'"))
  314. 'tall\'s,'
  315. >>> print(lpq.parse(r"'spaced name(x)'"))
  316. 'spaced name(x)'
  317. >>> print(lpq.parse(r"-'tall\'s,'(x)"))
  318. -'tall\'s,'(x)
  319. >>> print(lpq.parse(r"(man(x) & 'tall\'s,' (x) & walks (x) )"))
  320. (man(x) & 'tall\'s,'(x) & walks(x))
  321. Simplify
  322. ========
  323. >>> print(read_expr(r'\x.man(x)(john)').simplify())
  324. man(john)
  325. >>> print(read_expr(r'\x.((man(x)))(john)').simplify())
  326. man(john)
  327. >>> print(read_expr(r'\x.\y.sees(x,y)(john, mary)').simplify())
  328. sees(john,mary)
  329. >>> print(read_expr(r'\x y.sees(x,y)(john, mary)').simplify())
  330. sees(john,mary)
  331. >>> print(read_expr(r'\x.\y.sees(x,y)(john)(mary)').simplify())
  332. sees(john,mary)
  333. >>> print(read_expr(r'\x y.sees(x,y)(john)(mary)').simplify())
  334. sees(john,mary)
  335. >>> print(read_expr(r'\x.\y.sees(x,y)(john)').simplify())
  336. \y.sees(john,y)
  337. >>> print(read_expr(r'\x y.sees(x,y)(john)').simplify())
  338. \y.sees(john,y)
  339. >>> print(read_expr(r'(\x.\y.sees(x,y)(john))(mary)').simplify())
  340. sees(john,mary)
  341. >>> print(read_expr(r'(\x y.sees(x,y)(john))(mary)').simplify())
  342. sees(john,mary)
  343. >>> print(read_expr(r'exists x.(man(x) & (\x.exists y.walks(x,y))(x))').simplify())
  344. exists x.(man(x) & exists y.walks(x,y))
  345. >>> e1 = read_expr(r'exists x.(man(x) & (\x.exists y.walks(x,y))(y))').simplify()
  346. >>> e2 = read_expr(r'exists x.(man(x) & exists z1.walks(y,z1))')
  347. >>> e1 == e2
  348. True
  349. >>> print(read_expr(r'(\P Q.exists x.(P(x) & Q(x)))(\x.dog(x))').simplify())
  350. \Q.exists x.(dog(x) & Q(x))
  351. >>> print(read_expr(r'((\P.\Q.exists x.(P(x) & Q(x)))(\x.dog(x)))(\x.bark(x))').simplify())
  352. exists x.(dog(x) & bark(x))
  353. >>> print(read_expr(r'\P.(P(x)(y))(\a b.Q(a,b))').simplify())
  354. Q(x,y)
  355. Replace
  356. =======
  357. >>> a = read_expr(r'a')
  358. >>> x = read_expr(r'x')
  359. >>> y = read_expr(r'y')
  360. >>> z = read_expr(r'z')
  361. >>> print(read_expr(r'man(x)').replace(x.variable, a, False))
  362. man(a)
  363. >>> print(read_expr(r'(man(x) & tall(x))').replace(x.variable, a, False))
  364. (man(a) & tall(a))
  365. >>> print(read_expr(r'exists x.man(x)').replace(x.variable, a, False))
  366. exists x.man(x)
  367. >>> print(read_expr(r'exists x.man(x)').replace(x.variable, a, True))
  368. exists a.man(a)
  369. >>> print(read_expr(r'exists x.give(x,y,z)').replace(y.variable, a, False))
  370. exists x.give(x,a,z)
  371. >>> print(read_expr(r'exists x.give(x,y,z)').replace(y.variable, a, True))
  372. exists x.give(x,a,z)
  373. >>> e1 = read_expr(r'exists x.give(x,y,z)').replace(y.variable, x, False)
  374. >>> e2 = read_expr(r'exists z1.give(z1,x,z)')
  375. >>> e1 == e2
  376. True
  377. >>> e1 = read_expr(r'exists x.give(x,y,z)').replace(y.variable, x, True)
  378. >>> e2 = read_expr(r'exists z1.give(z1,x,z)')
  379. >>> e1 == e2
  380. True
  381. >>> print(read_expr(r'\x y z.give(x,y,z)').replace(y.variable, a, False))
  382. \x y z.give(x,y,z)
  383. >>> print(read_expr(r'\x y z.give(x,y,z)').replace(y.variable, a, True))
  384. \x a z.give(x,a,z)
  385. >>> print(read_expr(r'\x.\y.give(x,y,z)').replace(z.variable, a, False))
  386. \x y.give(x,y,a)
  387. >>> print(read_expr(r'\x.\y.give(x,y,z)').replace(z.variable, a, True))
  388. \x y.give(x,y,a)
  389. >>> e1 = read_expr(r'\x.\y.give(x,y,z)').replace(z.variable, x, False)
  390. >>> e2 = read_expr(r'\z1.\y.give(z1,y,x)')
  391. >>> e1 == e2
  392. True
  393. >>> e1 = read_expr(r'\x.\y.give(x,y,z)').replace(z.variable, x, True)
  394. >>> e2 = read_expr(r'\z1.\y.give(z1,y,x)')
  395. >>> e1 == e2
  396. True
  397. >>> print(read_expr(r'\x.give(x,y,z)').replace(z.variable, y, False))
  398. \x.give(x,y,y)
  399. >>> print(read_expr(r'\x.give(x,y,z)').replace(z.variable, y, True))
  400. \x.give(x,y,y)
  401. >>> from nltk.sem import logic
  402. >>> logic._counter._value = 0
  403. >>> e1 = read_expr('e1')
  404. >>> e2 = read_expr('e2')
  405. >>> print(read_expr('exists e1 e2.(walk(e1) & talk(e2))').replace(e1.variable, e2, True))
  406. exists e2 e01.(walk(e2) & talk(e01))
  407. Variables / Free
  408. ================
  409. >>> examples = [r'walk(john)',
  410. ... r'walk(x)',
  411. ... r'?vp(?np)',
  412. ... r'see(john,mary)',
  413. ... r'exists x.walk(x)',
  414. ... r'\x.see(john,x)',
  415. ... r'\x.see(john,x)(mary)',
  416. ... r'P(x)',
  417. ... r'\P.P(x)',
  418. ... r'aa(x,bb(y),cc(z),P(w),u)',
  419. ... r'bo(?det(?n),@x)']
  420. >>> examples = [read_expr(e) for e in examples]
  421. >>> for e in examples:
  422. ... print('%-25s' % e, sorted(e.free()))
  423. walk(john) []
  424. walk(x) [Variable('x')]
  425. ?vp(?np) []
  426. see(john,mary) []
  427. exists x.walk(x) []
  428. \x.see(john,x) []
  429. (\x.see(john,x))(mary) []
  430. P(x) [Variable('P'), Variable('x')]
  431. \P.P(x) [Variable('x')]
  432. aa(x,bb(y),cc(z),P(w),u) [Variable('P'), Variable('u'), Variable('w'), Variable('x'), Variable('y'), Variable('z')]
  433. bo(?det(?n),@x) []
  434. >>> for e in examples:
  435. ... print('%-25s' % e, sorted(e.constants()))
  436. walk(john) [Variable('john')]
  437. walk(x) []
  438. ?vp(?np) [Variable('?np')]
  439. see(john,mary) [Variable('john'), Variable('mary')]
  440. exists x.walk(x) []
  441. \x.see(john,x) [Variable('john')]
  442. (\x.see(john,x))(mary) [Variable('john'), Variable('mary')]
  443. P(x) []
  444. \P.P(x) []
  445. aa(x,bb(y),cc(z),P(w),u) []
  446. bo(?det(?n),@x) [Variable('?n'), Variable('@x')]
  447. >>> for e in examples:
  448. ... print('%-25s' % e, sorted(e.predicates()))
  449. walk(john) [Variable('walk')]
  450. walk(x) [Variable('walk')]
  451. ?vp(?np) [Variable('?vp')]
  452. see(john,mary) [Variable('see')]
  453. exists x.walk(x) [Variable('walk')]
  454. \x.see(john,x) [Variable('see')]
  455. (\x.see(john,x))(mary) [Variable('see')]
  456. P(x) []
  457. \P.P(x) []
  458. aa(x,bb(y),cc(z),P(w),u) [Variable('aa'), Variable('bb'), Variable('cc')]
  459. bo(?det(?n),@x) [Variable('?det'), Variable('bo')]
  460. >>> for e in examples:
  461. ... print('%-25s' % e, sorted(e.variables()))
  462. walk(john) []
  463. walk(x) [Variable('x')]
  464. ?vp(?np) [Variable('?np'), Variable('?vp')]
  465. see(john,mary) []
  466. exists x.walk(x) []
  467. \x.see(john,x) []
  468. (\x.see(john,x))(mary) []
  469. P(x) [Variable('P'), Variable('x')]
  470. \P.P(x) [Variable('x')]
  471. aa(x,bb(y),cc(z),P(w),u) [Variable('P'), Variable('u'), Variable('w'), Variable('x'), Variable('y'), Variable('z')]
  472. bo(?det(?n),@x) [Variable('?det'), Variable('?n'), Variable('@x')]
  473. `normalize`
  474. >>> print(read_expr(r'\e083.(walk(e083, z472) & talk(e092, z938))').normalize())
  475. \e01.(walk(e01,z3) & talk(e02,z4))
  476. Typed Logic
  477. +++++++++++
  478. >>> from nltk.sem.logic import LogicParser
  479. >>> tlp = LogicParser(True)
  480. >>> print(tlp.parse(r'man(x)').type)
  481. ?
  482. >>> print(tlp.parse(r'walk(angus)').type)
  483. ?
  484. >>> print(tlp.parse(r'-man(x)').type)
  485. t
  486. >>> print(tlp.parse(r'(man(x) <-> tall(x))').type)
  487. t
  488. >>> print(tlp.parse(r'exists x.(man(x) & tall(x))').type)
  489. t
  490. >>> print(tlp.parse(r'\x.man(x)').type)
  491. <e,?>
  492. >>> print(tlp.parse(r'john').type)
  493. e
  494. >>> print(tlp.parse(r'\x y.sees(x,y)').type)
  495. <e,<e,?>>
  496. >>> print(tlp.parse(r'\x.man(x)(john)').type)
  497. ?
  498. >>> print(tlp.parse(r'\x.\y.sees(x,y)(john)').type)
  499. <e,?>
  500. >>> print(tlp.parse(r'\x.\y.sees(x,y)(john)(mary)').type)
  501. ?
  502. >>> print(tlp.parse(r'\P.\Q.exists x.(P(x) & Q(x))').type)
  503. <<e,t>,<<e,t>,t>>
  504. >>> print(tlp.parse(r'\x.y').type)
  505. <?,e>
  506. >>> print(tlp.parse(r'\P.P(x)').type)
  507. <<e,?>,?>
  508. >>> parsed = tlp.parse('see(john,mary)')
  509. >>> print(parsed.type)
  510. ?
  511. >>> print(parsed.function)
  512. see(john)
  513. >>> print(parsed.function.type)
  514. <e,?>
  515. >>> print(parsed.function.function)
  516. see
  517. >>> print(parsed.function.function.type)
  518. <e,<e,?>>
  519. >>> parsed = tlp.parse('P(x,y)')
  520. >>> print(parsed)
  521. P(x,y)
  522. >>> print(parsed.type)
  523. ?
  524. >>> print(parsed.function)
  525. P(x)
  526. >>> print(parsed.function.type)
  527. <e,?>
  528. >>> print(parsed.function.function)
  529. P
  530. >>> print(parsed.function.function.type)
  531. <e,<e,?>>
  532. >>> print(tlp.parse(r'P').type)
  533. ?
  534. >>> print(tlp.parse(r'P', {'P': 't'}).type)
  535. t
  536. >>> a = tlp.parse(r'P(x)')
  537. >>> print(a.type)
  538. ?
  539. >>> print(a.function.type)
  540. <e,?>
  541. >>> print(a.argument.type)
  542. e
  543. >>> a = tlp.parse(r'-P(x)')
  544. >>> print(a.type)
  545. t
  546. >>> print(a.term.type)
  547. t
  548. >>> print(a.term.function.type)
  549. <e,t>
  550. >>> print(a.term.argument.type)
  551. e
  552. >>> a = tlp.parse(r'P & Q')
  553. >>> print(a.type)
  554. t
  555. >>> print(a.first.type)
  556. t
  557. >>> print(a.second.type)
  558. t
  559. >>> a = tlp.parse(r'(P(x) & Q(x))')
  560. >>> print(a.type)
  561. t
  562. >>> print(a.first.type)
  563. t
  564. >>> print(a.first.function.type)
  565. <e,t>
  566. >>> print(a.first.argument.type)
  567. e
  568. >>> print(a.second.type)
  569. t
  570. >>> print(a.second.function.type)
  571. <e,t>
  572. >>> print(a.second.argument.type)
  573. e
  574. >>> a = tlp.parse(r'\x.P(x)')
  575. >>> print(a.type)
  576. <e,?>
  577. >>> print(a.term.function.type)
  578. <e,?>
  579. >>> print(a.term.argument.type)
  580. e
  581. >>> a = tlp.parse(r'\P.P(x)')
  582. >>> print(a.type)
  583. <<e,?>,?>
  584. >>> print(a.term.function.type)
  585. <e,?>
  586. >>> print(a.term.argument.type)
  587. e
  588. >>> a = tlp.parse(r'(\x.P(x)(john)) & Q(x)')
  589. >>> print(a.type)
  590. t
  591. >>> print(a.first.type)
  592. t
  593. >>> print(a.first.function.type)
  594. <e,t>
  595. >>> print(a.first.function.term.function.type)
  596. <e,t>
  597. >>> print(a.first.function.term.argument.type)
  598. e
  599. >>> print(a.first.argument.type)
  600. e
  601. >>> a = tlp.parse(r'\x y.P(x,y)(john)(mary) & Q(x)')
  602. >>> print(a.type)
  603. t
  604. >>> print(a.first.type)
  605. t
  606. >>> print(a.first.function.type)
  607. <e,t>
  608. >>> print(a.first.function.function.type)
  609. <e,<e,t>>
  610. >>> a = tlp.parse(r'--P')
  611. >>> print(a.type)
  612. t
  613. >>> print(a.term.type)
  614. t
  615. >>> print(a.term.term.type)
  616. t
  617. >>> tlp.parse(r'\x y.P(x,y)').type
  618. <e,<e,?>>
  619. >>> tlp.parse(r'\x y.P(x,y)', {'P': '<e,<e,t>>'}).type
  620. <e,<e,t>>
  621. >>> a = tlp.parse(r'\P y.P(john,y)(\x y.see(x,y))')
  622. >>> a.type
  623. <e,?>
  624. >>> a.function.type
  625. <<e,<e,?>>,<e,?>>
  626. >>> a.function.term.term.function.function.type
  627. <e,<e,?>>
  628. >>> a.argument.type
  629. <e,<e,?>>
  630. >>> a = tlp.parse(r'exists c f.(father(c) = f)')
  631. >>> a.type
  632. t
  633. >>> a.term.term.type
  634. t
  635. >>> a.term.term.first.type
  636. e
  637. >>> a.term.term.first.function.type
  638. <e,e>
  639. >>> a.term.term.second.type
  640. e
  641. typecheck()
  642. >>> a = tlp.parse('P(x)')
  643. >>> b = tlp.parse('Q(x)')
  644. >>> a.type
  645. ?
  646. >>> c = a & b
  647. >>> c.first.type
  648. ?
  649. >>> c.typecheck() # doctest: +ELLIPSIS
  650. {...}
  651. >>> c.first.type
  652. t
  653. >>> a = tlp.parse('P(x)')
  654. >>> b = tlp.parse('P(x) & Q(x)')
  655. >>> a.type
  656. ?
  657. >>> typecheck([a,b]) # doctest: +ELLIPSIS
  658. {...}
  659. >>> a.type
  660. t
  661. >>> e = tlp.parse(r'man(x)')
  662. >>> print(dict((k,str(v)) for k,v in e.typecheck().items()) == {'x': 'e', 'man': '<e,?>'})
  663. True
  664. >>> sig = {'man': '<e, t>'}
  665. >>> e = tlp.parse(r'man(x)', sig)
  666. >>> print(e.function.type)
  667. <e,t>
  668. >>> print(dict((k,str(v)) for k,v in e.typecheck().items()) == {'x': 'e', 'man': '<e,t>'})
  669. True
  670. >>> print(e.function.type)
  671. <e,t>
  672. >>> print(dict((k,str(v)) for k,v in e.typecheck(sig).items()) == {'x': 'e', 'man': '<e,t>'})
  673. True
  674. findtype()
  675. >>> print(tlp.parse(r'man(x)').findtype(Variable('man')))
  676. <e,?>
  677. >>> print(tlp.parse(r'see(x,y)').findtype(Variable('see')))
  678. <e,<e,?>>
  679. >>> print(tlp.parse(r'P(Q(R(x)))').findtype(Variable('Q')))
  680. ?
  681. reading types from strings
  682. >>> Type.fromstring('e')
  683. e
  684. >>> Type.fromstring('<e,t>')
  685. <e,t>
  686. >>> Type.fromstring('<<e,t>,<e,t>>')
  687. <<e,t>,<e,t>>
  688. >>> Type.fromstring('<<e,?>,?>')
  689. <<e,?>,?>
  690. alternative type format
  691. >>> Type.fromstring('e').str()
  692. 'IND'
  693. >>> Type.fromstring('<e,?>').str()
  694. '(IND -> ANY)'
  695. >>> Type.fromstring('<<e,t>,t>').str()
  696. '((IND -> BOOL) -> BOOL)'
  697. Type.__eq__()
  698. >>> from nltk.sem.logic import *
  699. >>> e = ENTITY_TYPE
  700. >>> t = TRUTH_TYPE
  701. >>> a = ANY_TYPE
  702. >>> et = ComplexType(e,t)
  703. >>> eet = ComplexType(e,ComplexType(e,t))
  704. >>> at = ComplexType(a,t)
  705. >>> ea = ComplexType(e,a)
  706. >>> aa = ComplexType(a,a)
  707. >>> e == e
  708. True
  709. >>> t == t
  710. True
  711. >>> e == t
  712. False
  713. >>> a == t
  714. False
  715. >>> t == a
  716. False
  717. >>> a == a
  718. True
  719. >>> et == et
  720. True
  721. >>> a == et
  722. False
  723. >>> et == a
  724. False
  725. >>> a == ComplexType(a,aa)
  726. True
  727. >>> ComplexType(a,aa) == a
  728. True
  729. matches()
  730. >>> e.matches(t)
  731. False
  732. >>> a.matches(t)
  733. True
  734. >>> t.matches(a)
  735. True
  736. >>> a.matches(et)
  737. True
  738. >>> et.matches(a)
  739. True
  740. >>> ea.matches(eet)
  741. True
  742. >>> eet.matches(ea)
  743. True
  744. >>> aa.matches(et)
  745. True
  746. >>> aa.matches(t)
  747. True
  748. Type error during parsing
  749. =========================
  750. >>> try: print(tlp.parse(r'exists x y.(P(x) & P(x,y))'))
  751. ... except InconsistentTypeHierarchyException as e: print(e)
  752. The variable 'P' was found in multiple places with different types.
  753. >>> try: tlp.parse(r'\x y.see(x,y)(\x.man(x))')
  754. ... except TypeException as e: print(e)
  755. The function '\x y.see(x,y)' is of type '<e,<e,?>>' and cannot be applied to '\x.man(x)' of type '<e,?>'. Its argument must match type 'e'.
  756. >>> try: tlp.parse(r'\P x y.-P(x,y)(\x.-man(x))')
  757. ... except TypeException as e: print(e)
  758. The function '\P x y.-P(x,y)' is of type '<<e,<e,t>>,<e,<e,t>>>' and cannot be applied to '\x.-man(x)' of type '<e,t>'. Its argument must match type '<e,<e,t>>'.
  759. >>> a = tlp.parse(r'-talk(x)')
  760. >>> signature = a.typecheck()
  761. >>> try: print(tlp.parse(r'-talk(x,y)', signature))
  762. ... except InconsistentTypeHierarchyException as e: print(e)
  763. The variable 'talk' was found in multiple places with different types.
  764. >>> a = tlp.parse(r'-P(x)')
  765. >>> b = tlp.parse(r'-P(x,y)')
  766. >>> a.typecheck() # doctest: +ELLIPSIS
  767. {...}
  768. >>> b.typecheck() # doctest: +ELLIPSIS
  769. {...}
  770. >>> try: typecheck([a,b])
  771. ... except InconsistentTypeHierarchyException as e: print(e)
  772. The variable 'P' was found in multiple places with different types.
  773. >>> a = tlp.parse(r'P(x)')
  774. >>> b = tlp.parse(r'P(x,y)')
  775. >>> signature = {'P': '<e,t>'}
  776. >>> a.typecheck(signature) # doctest: +ELLIPSIS
  777. {...}
  778. >>> try: typecheck([a,b], signature)
  779. ... except InconsistentTypeHierarchyException as e: print(e)
  780. The variable 'P' was found in multiple places with different types.
  781. Parse errors
  782. ============
  783. >>> try: read_expr(r'')
  784. ... except LogicalExpressionException as e: print(e)
  785. End of input found. Expression expected.
  786. <BLANKLINE>
  787. ^
  788. >>> try: read_expr(r'(')
  789. ... except LogicalExpressionException as e: print(e)
  790. End of input found. Expression expected.
  791. (
  792. ^
  793. >>> try: read_expr(r')')
  794. ... except LogicalExpressionException as e: print(e)
  795. Unexpected token: ')'. Expression expected.
  796. )
  797. ^
  798. >>> try: read_expr(r'()')
  799. ... except LogicalExpressionException as e: print(e)
  800. Unexpected token: ')'. Expression expected.
  801. ()
  802. ^
  803. >>> try: read_expr(r'(P(x) & Q(x)')
  804. ... except LogicalExpressionException as e: print(e)
  805. End of input found. Expected token ')'.
  806. (P(x) & Q(x)
  807. ^
  808. >>> try: read_expr(r'(P(x) &')
  809. ... except LogicalExpressionException as e: print(e)
  810. End of input found. Expression expected.
  811. (P(x) &
  812. ^
  813. >>> try: read_expr(r'(P(x) | )')
  814. ... except LogicalExpressionException as e: print(e)
  815. Unexpected token: ')'. Expression expected.
  816. (P(x) | )
  817. ^
  818. >>> try: read_expr(r'P(x) ->')
  819. ... except LogicalExpressionException as e: print(e)
  820. End of input found. Expression expected.
  821. P(x) ->
  822. ^
  823. >>> try: read_expr(r'P(x')
  824. ... except LogicalExpressionException as e: print(e)
  825. End of input found. Expected token ')'.
  826. P(x
  827. ^
  828. >>> try: read_expr(r'P(x,')
  829. ... except LogicalExpressionException as e: print(e)
  830. End of input found. Expression expected.
  831. P(x,
  832. ^
  833. >>> try: read_expr(r'P(x,)')
  834. ... except LogicalExpressionException as e: print(e)
  835. Unexpected token: ')'. Expression expected.
  836. P(x,)
  837. ^
  838. >>> try: read_expr(r'exists')
  839. ... except LogicalExpressionException as e: print(e)
  840. End of input found. Variable and Expression expected following quantifier 'exists'.
  841. exists
  842. ^
  843. >>> try: read_expr(r'exists x')
  844. ... except LogicalExpressionException as e: print(e)
  845. End of input found. Expression expected.
  846. exists x
  847. ^
  848. >>> try: read_expr(r'exists x.')
  849. ... except LogicalExpressionException as e: print(e)
  850. End of input found. Expression expected.
  851. exists x.
  852. ^
  853. >>> try: read_expr(r'\ ')
  854. ... except LogicalExpressionException as e: print(e)
  855. End of input found. Variable and Expression expected following lambda operator.
  856. \
  857. ^
  858. >>> try: read_expr(r'\ x')
  859. ... except LogicalExpressionException as e: print(e)
  860. End of input found. Expression expected.
  861. \ x
  862. ^
  863. >>> try: read_expr(r'\ x y')
  864. ... except LogicalExpressionException as e: print(e)
  865. End of input found. Expression expected.
  866. \ x y
  867. ^
  868. >>> try: read_expr(r'\ x.')
  869. ... except LogicalExpressionException as e: print(e)
  870. End of input found. Expression expected.
  871. \ x.
  872. ^
  873. >>> try: read_expr(r'P(x)Q(x)')
  874. ... except LogicalExpressionException as e: print(e)
  875. Unexpected token: 'Q'.
  876. P(x)Q(x)
  877. ^
  878. >>> try: read_expr(r'(P(x)Q(x)')
  879. ... except LogicalExpressionException as e: print(e)
  880. Unexpected token: 'Q'. Expected token ')'.
  881. (P(x)Q(x)
  882. ^
  883. >>> try: read_expr(r'exists x y')
  884. ... except LogicalExpressionException as e: print(e)
  885. End of input found. Expression expected.
  886. exists x y
  887. ^
  888. >>> try: read_expr(r'exists x y.')
  889. ... except LogicalExpressionException as e: print(e)
  890. End of input found. Expression expected.
  891. exists x y.
  892. ^
  893. >>> try: read_expr(r'exists x -> y')
  894. ... except LogicalExpressionException as e: print(e)
  895. Unexpected token: '->'. Expression expected.
  896. exists x -> y
  897. ^
  898. >>> try: read_expr(r'A -> ((P(x) & Q(x)) -> Z')
  899. ... except LogicalExpressionException as e: print(e)
  900. End of input found. Expected token ')'.
  901. A -> ((P(x) & Q(x)) -> Z
  902. ^
  903. >>> try: read_expr(r'A -> ((P(x) &) -> Z')
  904. ... except LogicalExpressionException as e: print(e)
  905. Unexpected token: ')'. Expression expected.
  906. A -> ((P(x) &) -> Z
  907. ^
  908. >>> try: read_expr(r'A -> ((P(x) | )) -> Z')
  909. ... except LogicalExpressionException as e: print(e)
  910. Unexpected token: ')'. Expression expected.
  911. A -> ((P(x) | )) -> Z
  912. ^
  913. >>> try: read_expr(r'A -> (P(x) ->) -> Z')
  914. ... except LogicalExpressionException as e: print(e)
  915. Unexpected token: ')'. Expression expected.
  916. A -> (P(x) ->) -> Z
  917. ^
  918. >>> try: read_expr(r'A -> (P(x) -> Z')
  919. ... except LogicalExpressionException as e: print(e)
  920. End of input found. Expected token ')'.
  921. A -> (P(x) -> Z
  922. ^
  923. >>> try: read_expr(r'A -> (P(x,) -> Z')
  924. ... except LogicalExpressionException as e: print(e)
  925. Unexpected token: ')'. Expression expected.
  926. A -> (P(x,) -> Z
  927. ^
  928. >>> try: read_expr(r'A -> (P(x,)) -> Z')
  929. ... except LogicalExpressionException as e: print(e)
  930. Unexpected token: ')'. Expression expected.
  931. A -> (P(x,)) -> Z
  932. ^
  933. >>> try: read_expr(r'A -> (exists) -> Z')
  934. ... except LogicalExpressionException as e: print(e)
  935. ')' is an illegal variable name. Constants may not be quantified.
  936. A -> (exists) -> Z
  937. ^
  938. >>> try: read_expr(r'A -> (exists x) -> Z')
  939. ... except LogicalExpressionException as e: print(e)
  940. Unexpected token: ')'. Expression expected.
  941. A -> (exists x) -> Z
  942. ^
  943. >>> try: read_expr(r'A -> (exists x.) -> Z')
  944. ... except LogicalExpressionException as e: print(e)
  945. Unexpected token: ')'. Expression expected.
  946. A -> (exists x.) -> Z
  947. ^
  948. >>> try: read_expr(r'A -> (\ ) -> Z')
  949. ... except LogicalExpressionException as e: print(e)
  950. ')' is an illegal variable name. Constants may not be abstracted.
  951. A -> (\ ) -> Z
  952. ^
  953. >>> try: read_expr(r'A -> (\ x) -> Z')
  954. ... except LogicalExpressionException as e: print(e)
  955. Unexpected token: ')'. Expression expected.
  956. A -> (\ x) -> Z
  957. ^
  958. >>> try: read_expr(r'A -> (\ x y) -> Z')
  959. ... except LogicalExpressionException as e: print(e)
  960. Unexpected token: ')'. Expression expected.
  961. A -> (\ x y) -> Z
  962. ^
  963. >>> try: read_expr(r'A -> (\ x.) -> Z')
  964. ... except LogicalExpressionException as e: print(e)
  965. Unexpected token: ')'. Expression expected.
  966. A -> (\ x.) -> Z
  967. ^
  968. >>> try: read_expr(r'A -> (P(x)Q(x)) -> Z')
  969. ... except LogicalExpressionException as e: print(e)
  970. Unexpected token: 'Q'. Expected token ')'.
  971. A -> (P(x)Q(x)) -> Z
  972. ^
  973. >>> try: read_expr(r'A -> ((P(x)Q(x)) -> Z')
  974. ... except LogicalExpressionException as e: print(e)
  975. Unexpected token: 'Q'. Expected token ')'.
  976. A -> ((P(x)Q(x)) -> Z
  977. ^
  978. >>> try: read_expr(r'A -> (all x y) -> Z')
  979. ... except LogicalExpressionException as e: print(e)
  980. Unexpected token: ')'. Expression expected.
  981. A -> (all x y) -> Z
  982. ^
  983. >>> try: read_expr(r'A -> (exists x y.) -> Z')
  984. ... except LogicalExpressionException as e: print(e)
  985. Unexpected token: ')'. Expression expected.
  986. A -> (exists x y.) -> Z
  987. ^
  988. >>> try: read_expr(r'A -> (exists x -> y) -> Z')
  989. ... except LogicalExpressionException as e: print(e)
  990. Unexpected token: '->'. Expression expected.
  991. A -> (exists x -> y) -> Z
  992. ^