cooper_storage.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. # Natural Language Toolkit: Cooper storage for Quantifier Ambiguity
  2. #
  3. # Copyright (C) 2001-2020 NLTK Project
  4. # Author: Ewan Klein <ewan@inf.ed.ac.uk>
  5. # URL: <http://nltk.org/>
  6. # For license information, see LICENSE.TXT
  7. from nltk.sem.logic import LambdaExpression, ApplicationExpression, Variable
  8. from nltk.parse import load_parser
  9. from nltk.parse.featurechart import InstantiateVarsChart
  10. class CooperStore(object):
  11. """
  12. A container for handling quantifier ambiguity via Cooper storage.
  13. """
  14. def __init__(self, featstruct):
  15. """
  16. :param featstruct: The value of the ``sem`` node in a tree from
  17. ``parse_with_bindops()``
  18. :type featstruct: FeatStruct (with features ``core`` and ``store``)
  19. """
  20. self.featstruct = featstruct
  21. self.readings = []
  22. try:
  23. self.core = featstruct["CORE"]
  24. self.store = featstruct["STORE"]
  25. except KeyError:
  26. print("%s is not a Cooper storage structure" % featstruct)
  27. def _permute(self, lst):
  28. """
  29. :return: An iterator over the permutations of the input list
  30. :type lst: list
  31. :rtype: iter
  32. """
  33. remove = lambda lst0, index: lst0[:index] + lst0[index + 1 :]
  34. if lst:
  35. for index, x in enumerate(lst):
  36. for y in self._permute(remove(lst, index)):
  37. yield (x,) + y
  38. else:
  39. yield ()
  40. def s_retrieve(self, trace=False):
  41. """
  42. Carry out S-Retrieval of binding operators in store. If hack=True,
  43. serialize the bindop and core as strings and reparse. Ugh.
  44. Each permutation of the store (i.e. list of binding operators) is
  45. taken to be a possible scoping of quantifiers. We iterate through the
  46. binding operators in each permutation, and successively apply them to
  47. the current term, starting with the core semantic representation,
  48. working from the inside out.
  49. Binding operators are of the form::
  50. bo(\P.all x.(man(x) -> P(x)),z1)
  51. """
  52. for perm, store_perm in enumerate(self._permute(self.store)):
  53. if trace:
  54. print("Permutation %s" % (perm + 1))
  55. term = self.core
  56. for bindop in store_perm:
  57. # we just want the arguments that are wrapped by the 'bo' predicate
  58. quant, varex = tuple(bindop.args)
  59. # use var to make an abstraction over the current term and then
  60. # apply the quantifier to it
  61. term = ApplicationExpression(
  62. quant, LambdaExpression(varex.variable, term)
  63. )
  64. if trace:
  65. print(" ", term)
  66. term = term.simplify()
  67. self.readings.append(term)
  68. def parse_with_bindops(sentence, grammar=None, trace=0):
  69. """
  70. Use a grammar with Binding Operators to parse a sentence.
  71. """
  72. if not grammar:
  73. grammar = "grammars/book_grammars/storage.fcfg"
  74. parser = load_parser(grammar, trace=trace, chart_class=InstantiateVarsChart)
  75. # Parse the sentence.
  76. tokens = sentence.split()
  77. return list(parser.parse(tokens))
  78. def demo():
  79. from nltk.sem import cooper_storage as cs
  80. sentence = "every girl chases a dog"
  81. # sentence = "a man gives a bone to every dog"
  82. print()
  83. print("Analyis of sentence '%s'" % sentence)
  84. print("=" * 50)
  85. trees = cs.parse_with_bindops(sentence, trace=0)
  86. for tree in trees:
  87. semrep = cs.CooperStore(tree.label()["SEM"])
  88. print()
  89. print("Binding operators:")
  90. print("-" * 15)
  91. for s in semrep.store:
  92. print(s)
  93. print()
  94. print("Core:")
  95. print("-" * 15)
  96. print(semrep.core)
  97. print()
  98. print("S-Retrieval:")
  99. print("-" * 15)
  100. semrep.s_retrieve(trace=True)
  101. print("Readings:")
  102. print("-" * 15)
  103. for i, reading in enumerate(semrep.readings):
  104. print("%s: %s" % (i + 1, reading))
  105. if __name__ == "__main__":
  106. demo()