.. Copyright (C) 2001-2020 NLTK Project .. For license information, see LICENSE.TXT ============================================================================== Glue Semantics ============================================================================== .. include:: ../../../nltk_book/definitions.rst ====================== Linear logic ====================== >>> from nltk.sem import logic >>> from nltk.sem.glue import * >>> from nltk.sem.linearlogic import * >>> from nltk.sem.linearlogic import Expression >>> read_expr = Expression.fromstring Parser >>> print(read_expr(r'f')) f >>> print(read_expr(r'(g -o f)')) (g -o f) >>> print(read_expr(r'(g -o (h -o f))')) (g -o (h -o f)) >>> print(read_expr(r'((g -o G) -o G)')) ((g -o G) -o G) >>> print(read_expr(r'(g -o f)(g)')) (g -o f)(g) >>> print(read_expr(r'((g -o G) -o G)((g -o f))')) ((g -o G) -o G)((g -o f)) Simplify >>> print(read_expr(r'f').simplify()) f >>> print(read_expr(r'(g -o f)').simplify()) (g -o f) >>> print(read_expr(r'((g -o G) -o G)').simplify()) ((g -o G) -o G) >>> print(read_expr(r'(g -o f)(g)').simplify()) f >>> try: read_expr(r'(g -o f)(f)').simplify() ... except LinearLogicApplicationException as e: print(e) ... Cannot apply (g -o f) to f. Cannot unify g with f given {} >>> print(read_expr(r'(G -o f)(g)').simplify()) f >>> print(read_expr(r'((g -o G) -o G)((g -o f))').simplify()) f Test BindingDict >>> h = ConstantExpression('h') >>> g = ConstantExpression('g') >>> f = ConstantExpression('f') >>> H = VariableExpression('H') >>> G = VariableExpression('G') >>> F = VariableExpression('F') >>> d1 = BindingDict({H: h}) >>> d2 = BindingDict({F: f, G: F}) >>> d12 = d1 + d2 >>> all12 = ['%s: %s' % (v, d12[v]) for v in d12.d] >>> all12.sort() >>> print(all12) ['F: f', 'G: f', 'H: h'] >>> BindingDict([(F,f),(G,g),(H,h)]) == BindingDict({F:f, G:g, H:h}) True >>> d4 = BindingDict({F: f}) >>> try: d4[F] = g ... except VariableBindingException as e: print(e) Variable F already bound to another value Test Unify >>> try: f.unify(g, BindingDict()) ... except UnificationException as e: print(e) ... Cannot unify f with g given {} >>> f.unify(G, BindingDict()) == BindingDict({G: f}) True >>> try: f.unify(G, BindingDict({G: h})) ... except UnificationException as e: print(e) ... Cannot unify f with G given {G: h} >>> f.unify(G, BindingDict({G: f})) == BindingDict({G: f}) True >>> f.unify(G, BindingDict({H: f})) == BindingDict({G: f, H: f}) True >>> G.unify(f, BindingDict()) == BindingDict({G: f}) True >>> try: G.unify(f, BindingDict({G: h})) ... except UnificationException as e: print(e) ... Cannot unify G with f given {G: h} >>> G.unify(f, BindingDict({G: f})) == BindingDict({G: f}) True >>> G.unify(f, BindingDict({H: f})) == BindingDict({G: f, H: f}) True >>> G.unify(F, BindingDict()) == BindingDict({G: F}) True >>> try: G.unify(F, BindingDict({G: H})) ... except UnificationException as e: print(e) ... Cannot unify G with F given {G: H} >>> G.unify(F, BindingDict({G: F})) == BindingDict({G: F}) True >>> G.unify(F, BindingDict({H: F})) == BindingDict({G: F, H: F}) True Test Compile >>> print(read_expr('g').compile_pos(Counter(), GlueFormula)) (, []) >>> print(read_expr('(g -o f)').compile_pos(Counter(), GlueFormula)) (, []) >>> print(read_expr('(g -o (h -o f))').compile_pos(Counter(), GlueFormula)) (, []) ====================== Glue ====================== Demo of "John walks" -------------------- >>> john = GlueFormula("John", "g") >>> print(john) John : g >>> walks = GlueFormula(r"\x.walks(x)", "(g -o f)") >>> print(walks) \x.walks(x) : (g -o f) >>> print(walks.applyto(john)) \x.walks(x)(John) : (g -o f)(g) >>> print(walks.applyto(john).simplify()) walks(John) : f Demo of "A dog walks" --------------------- >>> a = GlueFormula("\P Q.some x.(P(x) and Q(x))", "((gv -o gr) -o ((g -o G) -o G))") >>> print(a) \P Q.exists x.(P(x) & Q(x)) : ((gv -o gr) -o ((g -o G) -o G)) >>> man = GlueFormula(r"\x.man(x)", "(gv -o gr)") >>> print(man) \x.man(x) : (gv -o gr) >>> walks = GlueFormula(r"\x.walks(x)", "(g -o f)") >>> print(walks) \x.walks(x) : (g -o f) >>> a_man = a.applyto(man) >>> print(a_man.simplify()) \Q.exists x.(man(x) & Q(x)) : ((g -o G) -o G) >>> a_man_walks = a_man.applyto(walks) >>> print(a_man_walks.simplify()) exists x.(man(x) & walks(x)) : f Demo of 'every girl chases a dog' --------------------------------- Individual words: >>> every = GlueFormula("\P Q.all x.(P(x) -> Q(x))", "((gv -o gr) -o ((g -o G) -o G))") >>> print(every) \P Q.all x.(P(x) -> Q(x)) : ((gv -o gr) -o ((g -o G) -o G)) >>> girl = GlueFormula(r"\x.girl(x)", "(gv -o gr)") >>> print(girl) \x.girl(x) : (gv -o gr) >>> chases = GlueFormula(r"\x y.chases(x,y)", "(g -o (h -o f))") >>> print(chases) \x y.chases(x,y) : (g -o (h -o f)) >>> a = GlueFormula("\P Q.some x.(P(x) and Q(x))", "((hv -o hr) -o ((h -o H) -o H))") >>> print(a) \P Q.exists x.(P(x) & Q(x)) : ((hv -o hr) -o ((h -o H) -o H)) >>> dog = GlueFormula(r"\x.dog(x)", "(hv -o hr)") >>> print(dog) \x.dog(x) : (hv -o hr) Noun Quantification can only be done one way: >>> every_girl = every.applyto(girl) >>> print(every_girl.simplify()) \Q.all x.(girl(x) -> Q(x)) : ((g -o G) -o G) >>> a_dog = a.applyto(dog) >>> print(a_dog.simplify()) \Q.exists x.(dog(x) & Q(x)) : ((h -o H) -o H) The first reading is achieved by combining 'chases' with 'a dog' first. Since 'a girl' requires something of the form '(h -o H)' we must get rid of the 'g' in the glue of 'see'. We will do this with the '-o elimination' rule. So, x1 will be our subject placeholder. >>> xPrime = GlueFormula("x1", "g") >>> print(xPrime) x1 : g >>> xPrime_chases = chases.applyto(xPrime) >>> print(xPrime_chases.simplify()) \y.chases(x1,y) : (h -o f) >>> xPrime_chases_a_dog = a_dog.applyto(xPrime_chases) >>> print(xPrime_chases_a_dog.simplify()) exists x.(dog(x) & chases(x1,x)) : f Now we can retract our subject placeholder using lambda-abstraction and combine with the true subject. >>> chases_a_dog = xPrime_chases_a_dog.lambda_abstract(xPrime) >>> print(chases_a_dog.simplify()) \x1.exists x.(dog(x) & chases(x1,x)) : (g -o f) >>> every_girl_chases_a_dog = every_girl.applyto(chases_a_dog) >>> r1 = every_girl_chases_a_dog.simplify() >>> r2 = GlueFormula(r'all x.(girl(x) -> exists z1.(dog(z1) & chases(x,z1)))', 'f') >>> r1 == r2 True The second reading is achieved by combining 'every girl' with 'chases' first. >>> xPrime = GlueFormula("x1", "g") >>> print(xPrime) x1 : g >>> xPrime_chases = chases.applyto(xPrime) >>> print(xPrime_chases.simplify()) \y.chases(x1,y) : (h -o f) >>> yPrime = GlueFormula("x2", "h") >>> print(yPrime) x2 : h >>> xPrime_chases_yPrime = xPrime_chases.applyto(yPrime) >>> print(xPrime_chases_yPrime.simplify()) chases(x1,x2) : f >>> chases_yPrime = xPrime_chases_yPrime.lambda_abstract(xPrime) >>> print(chases_yPrime.simplify()) \x1.chases(x1,x2) : (g -o f) >>> every_girl_chases_yPrime = every_girl.applyto(chases_yPrime) >>> print(every_girl_chases_yPrime.simplify()) all x.(girl(x) -> chases(x,x2)) : f >>> every_girl_chases = every_girl_chases_yPrime.lambda_abstract(yPrime) >>> print(every_girl_chases.simplify()) \x2.all x.(girl(x) -> chases(x,x2)) : (h -o f) >>> every_girl_chases_a_dog = a_dog.applyto(every_girl_chases) >>> r1 = every_girl_chases_a_dog.simplify() >>> r2 = GlueFormula(r'exists x.(dog(x) & all z2.(girl(z2) -> chases(z2,x)))', 'f') >>> r1 == r2 True Compilation ----------- >>> for cp in GlueFormula('m', '(b -o a)').compile(Counter()): print(cp) m : (b -o a) : {1} >>> for cp in GlueFormula('m', '((c -o b) -o a)').compile(Counter()): print(cp) v1 : c : {1} m : (b[1] -o a) : {2} >>> for cp in GlueFormula('m', '((d -o (c -o b)) -o a)').compile(Counter()): print(cp) v1 : c : {1} v2 : d : {2} m : (b[1, 2] -o a) : {3} >>> for cp in GlueFormula('m', '((d -o e) -o ((c -o b) -o a))').compile(Counter()): print(cp) v1 : d : {1} v2 : c : {2} m : (e[1] -o (b[2] -o a)) : {3} >>> for cp in GlueFormula('m', '(((d -o c) -o b) -o a)').compile(Counter()): print(cp) v1 : (d -o c) : {1} m : (b[1] -o a) : {2} >>> for cp in GlueFormula('m', '((((e -o d) -o c) -o b) -o a)').compile(Counter()): print(cp) v1 : e : {1} v2 : (d[1] -o c) : {2} m : (b[2] -o a) : {3} Demo of 'a man walks' using Compilation --------------------------------------- Premises >>> a = GlueFormula('\\P Q.some x.(P(x) and Q(x))', '((gv -o gr) -o ((g -o G) -o G))') >>> print(a) \P Q.exists x.(P(x) & Q(x)) : ((gv -o gr) -o ((g -o G) -o G)) >>> man = GlueFormula('\\x.man(x)', '(gv -o gr)') >>> print(man) \x.man(x) : (gv -o gr) >>> walks = GlueFormula('\\x.walks(x)', '(g -o f)') >>> print(walks) \x.walks(x) : (g -o f) Compiled Premises: >>> counter = Counter() >>> ahc = a.compile(counter) >>> g1 = ahc[0] >>> print(g1) v1 : gv : {1} >>> g2 = ahc[1] >>> print(g2) v2 : g : {2} >>> g3 = ahc[2] >>> print(g3) \P Q.exists x.(P(x) & Q(x)) : (gr[1] -o (G[2] -o G)) : {3} >>> g4 = man.compile(counter)[0] >>> print(g4) \x.man(x) : (gv -o gr) : {4} >>> g5 = walks.compile(counter)[0] >>> print(g5) \x.walks(x) : (g -o f) : {5} Derivation: >>> g14 = g4.applyto(g1) >>> print(g14.simplify()) man(v1) : gr : {1, 4} >>> g134 = g3.applyto(g14) >>> print(g134.simplify()) \Q.exists x.(man(x) & Q(x)) : (G[2] -o G) : {1, 3, 4} >>> g25 = g5.applyto(g2) >>> print(g25.simplify()) walks(v2) : f : {2, 5} >>> g12345 = g134.applyto(g25) >>> print(g12345.simplify()) exists x.(man(x) & walks(x)) : f : {1, 2, 3, 4, 5} --------------------------------- Dependency Graph to Glue Formulas --------------------------------- >>> from nltk.corpus.reader.dependency import DependencyGraph >>> depgraph = DependencyGraph("""1 John _ NNP NNP _ 2 SUBJ _ _ ... 2 sees _ VB VB _ 0 ROOT _ _ ... 3 a _ ex_quant ex_quant _ 4 SPEC _ _ ... 4 dog _ NN NN _ 2 OBJ _ _ ... """) >>> gfl = GlueDict('nltk:grammars/sample_grammars/glue.semtype').to_glueformula_list(depgraph) >>> print(gfl) # doctest: +SKIP [\x y.sees(x,y) : (f -o (i -o g)), \x.dog(x) : (iv -o ir), \P Q.exists x.(P(x) & Q(x)) : ((iv -o ir) -o ((i -o I3) -o I3)), \P Q.exists x.(P(x) & Q(x)) : ((fv -o fr) -o ((f -o F4) -o F4)), \x.John(x) : (fv -o fr)] >>> glue = Glue() >>> for r in sorted([r.simplify().normalize() for r in glue.get_readings(glue.gfl_to_compiled(gfl))], key=str): ... print(r) exists z1.(John(z1) & exists z2.(dog(z2) & sees(z1,z2))) exists z1.(dog(z1) & exists z2.(John(z2) & sees(z2,z1))) ----------------------------------- Dependency Graph to LFG f-structure ----------------------------------- >>> from nltk.sem.lfg import FStructure >>> fstruct = FStructure.read_depgraph(depgraph) >>> print(fstruct) # doctest: +SKIP f:[pred 'sees' obj h:[pred 'dog' spec 'a'] subj g:[pred 'John']] >>> fstruct.to_depgraph().tree().pprint() (sees (dog a) John) --------------------------------- LFG f-structure to Glue --------------------------------- >>> fstruct.to_glueformula_list(GlueDict('nltk:grammars/sample_grammars/glue.semtype')) # doctest: +SKIP [\x y.sees(x,y) : (i -o (g -o f)), \x.dog(x) : (gv -o gr), \P Q.exists x.(P(x) & Q(x)) : ((gv -o gr) -o ((g -o G3) -o G3)), \P Q.exists x.(P(x) & Q(x)) : ((iv -o ir) -o ((i -o I4) -o I4)), \x.John(x) : (iv -o ir)] .. see gluesemantics_malt.doctest for more