skolemize.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. # Natural Language Toolkit: Semantic Interpretation
  2. #
  3. # Author: Ewan Klein <ewan@inf.ed.ac.uk>
  4. #
  5. # Copyright (C) 2001-2019 NLTK Project
  6. # URL: <http://nltk.org/>
  7. # For license information, see LICENSE.TXT
  8. from nltk.sem.logic import (
  9. AllExpression,
  10. AndExpression,
  11. ApplicationExpression,
  12. EqualityExpression,
  13. ExistsExpression,
  14. IffExpression,
  15. ImpExpression,
  16. NegatedExpression,
  17. OrExpression,
  18. VariableExpression,
  19. skolem_function,
  20. unique_variable,
  21. )
  22. def skolemize(expression, univ_scope=None, used_variables=None):
  23. """
  24. Skolemize the expression and convert to conjunctive normal form (CNF)
  25. """
  26. if univ_scope is None:
  27. univ_scope = set()
  28. if used_variables is None:
  29. used_variables = set()
  30. if isinstance(expression, AllExpression):
  31. term = skolemize(
  32. expression.term,
  33. univ_scope | set([expression.variable]),
  34. used_variables | set([expression.variable]),
  35. )
  36. return term.replace(
  37. expression.variable,
  38. VariableExpression(unique_variable(ignore=used_variables)),
  39. )
  40. elif isinstance(expression, AndExpression):
  41. return skolemize(expression.first, univ_scope, used_variables) & skolemize(
  42. expression.second, univ_scope, used_variables
  43. )
  44. elif isinstance(expression, OrExpression):
  45. return to_cnf(
  46. skolemize(expression.first, univ_scope, used_variables),
  47. skolemize(expression.second, univ_scope, used_variables),
  48. )
  49. elif isinstance(expression, ImpExpression):
  50. return to_cnf(
  51. skolemize(-expression.first, univ_scope, used_variables),
  52. skolemize(expression.second, univ_scope, used_variables),
  53. )
  54. elif isinstance(expression, IffExpression):
  55. return to_cnf(
  56. skolemize(-expression.first, univ_scope, used_variables),
  57. skolemize(expression.second, univ_scope, used_variables),
  58. ) & to_cnf(
  59. skolemize(expression.first, univ_scope, used_variables),
  60. skolemize(-expression.second, univ_scope, used_variables),
  61. )
  62. elif isinstance(expression, EqualityExpression):
  63. return expression
  64. elif isinstance(expression, NegatedExpression):
  65. negated = expression.term
  66. if isinstance(negated, AllExpression):
  67. term = skolemize(
  68. -negated.term, univ_scope, used_variables | set([negated.variable])
  69. )
  70. if univ_scope:
  71. return term.replace(negated.variable, skolem_function(univ_scope))
  72. else:
  73. skolem_constant = VariableExpression(
  74. unique_variable(ignore=used_variables)
  75. )
  76. return term.replace(negated.variable, skolem_constant)
  77. elif isinstance(negated, AndExpression):
  78. return to_cnf(
  79. skolemize(-negated.first, univ_scope, used_variables),
  80. skolemize(-negated.second, univ_scope, used_variables),
  81. )
  82. elif isinstance(negated, OrExpression):
  83. return skolemize(-negated.first, univ_scope, used_variables) & skolemize(
  84. -negated.second, univ_scope, used_variables
  85. )
  86. elif isinstance(negated, ImpExpression):
  87. return skolemize(negated.first, univ_scope, used_variables) & skolemize(
  88. -negated.second, univ_scope, used_variables
  89. )
  90. elif isinstance(negated, IffExpression):
  91. return to_cnf(
  92. skolemize(-negated.first, univ_scope, used_variables),
  93. skolemize(-negated.second, univ_scope, used_variables),
  94. ) & to_cnf(
  95. skolemize(negated.first, univ_scope, used_variables),
  96. skolemize(negated.second, univ_scope, used_variables),
  97. )
  98. elif isinstance(negated, EqualityExpression):
  99. return expression
  100. elif isinstance(negated, NegatedExpression):
  101. return skolemize(negated.term, univ_scope, used_variables)
  102. elif isinstance(negated, ExistsExpression):
  103. term = skolemize(
  104. -negated.term,
  105. univ_scope | set([negated.variable]),
  106. used_variables | set([negated.variable]),
  107. )
  108. return term.replace(
  109. negated.variable,
  110. VariableExpression(unique_variable(ignore=used_variables)),
  111. )
  112. elif isinstance(negated, ApplicationExpression):
  113. return expression
  114. else:
  115. raise Exception('\'%s\' cannot be skolemized' % expression)
  116. elif isinstance(expression, ExistsExpression):
  117. term = skolemize(
  118. expression.term, univ_scope, used_variables | set([expression.variable])
  119. )
  120. if univ_scope:
  121. return term.replace(expression.variable, skolem_function(univ_scope))
  122. else:
  123. skolem_constant = VariableExpression(unique_variable(ignore=used_variables))
  124. return term.replace(expression.variable, skolem_constant)
  125. elif isinstance(expression, ApplicationExpression):
  126. return expression
  127. else:
  128. raise Exception('\'%s\' cannot be skolemized' % expression)
  129. def to_cnf(first, second):
  130. """
  131. Convert this split disjunction to conjunctive normal form (CNF)
  132. """
  133. if isinstance(first, AndExpression):
  134. r_first = to_cnf(first.first, second)
  135. r_second = to_cnf(first.second, second)
  136. return r_first & r_second
  137. elif isinstance(second, AndExpression):
  138. r_first = to_cnf(first, second.first)
  139. r_second = to_cnf(first, second.second)
  140. return r_first & r_second
  141. else:
  142. return first | second