1
2
3
4
5
6
7
8
9 from logic import *
10
11
12 try:
13 from Tkinter import Canvas
14 from Tkinter import Tk
15 from tkFont import Font
16 from nltk.util import in_idle
17
18 except ImportError:
34
37 """
38 This is the base abstract DRT Expression from which every DRT
39 Expression extends.
40 """
41
44
47
49 raise NotImplementedError()
50
54
62
63 - def equiv(self, other, prover=None):
64 """
65 Check for logical equivalence.
66 Pass the expression (self <-> other) to the theorem prover.
67 If the prover says it is valid, then the self and other are equal.
68
69 @param other: an C{AbstractDrs} to check equality against
70 @param prover: a C{nltk.inference.api.Prover}
71 """
72 assert isinstance(other, AbstractDrs)
73
74 f1 = self.simplify().fol();
75 f2 = other.simplify().fol();
76 return f1.equiv(f2, prover)
77
79 raise AttributeError("'%s' object has no attribute 'type'" %
80 self.__class__.__name__)
81 type = property(_get_type)
82
84 raise NotImplementedError()
85
88
90 """
91 Return the set of discourse referents in this DRS.
92 @param recursive: C{boolean} Also find discourse referents in subterms?
93 @return: C{list} of C{Variable}s
94 """
95 raise NotImplementedError()
96
103
106
109
112
114 def combinator(a, *additional):
115 if len(additional) == 0:
116 return self.__class__(a)
117 elif len(additional) == 1:
118 return self.__class__(a, additional[0])
119
120 return self.visit(lambda e: isinstance(e,Variable)
121 and e or e.eliminate_equality(), combinator, set())
122
123
125 """
126 Draw the DRS
127 """
128 print self.pretty()
129
131 """
132 Draw the DRS
133 @return: the pretty print string
134 """
135 return '\n'.join(self._pretty())
136
139
140
141 -class DRS(AbstractDrs, Expression):
142 """A Discourse Representation Structure."""
143 - def __init__(self, refs, conds, consequent=None):
144 """
145 @param refs: C{list} of C{DrtIndividualVariableExpression} for the
146 discourse referents
147 @param conds: C{list} of C{Expression} for the conditions
148 """
149 self.refs = refs
150 self.conds = conds
151 self.consequent = consequent
152
153 - def replace(self, variable, expression, replace_bound=False, alpha_convert=True):
154 """Replace all instances of variable v with expression E in self,
155 where v is free in self."""
156 if variable in self.refs:
157
158 if not replace_bound:
159 return self
160 else:
161 i = self.refs.index(variable)
162 if self.consequent:
163 consequent = self.consequent.replace(variable, expression, True, alpha_convert)
164 else:
165 consequent = None
166 return DRS(self.refs[:i]+[expression.variable]+self.refs[i+1:],
167 [cond.replace(variable, expression, True, alpha_convert)
168 for cond in self.conds],
169 consequent)
170 else:
171 if alpha_convert:
172
173
174 for ref in (set(self.refs) & expression.free()):
175 newvar = unique_variable(ref)
176 newvarex = DrtVariableExpression(newvar)
177 i = self.refs.index(ref)
178 if self.consequent:
179 consequent = self.consequent.replace(ref, newvarex, True, alpha_convert)
180 else:
181 consequent = None
182 self = DRS(self.refs[:i]+[newvar]+self.refs[i+1:],
183 [cond.replace(ref, newvarex, True, alpha_convert)
184 for cond in self.conds],
185 consequent)
186
187
188 if self.consequent:
189 consequent = self.consequent.replace(variable, expression, replace_bound, alpha_convert)
190 else:
191 consequent = None
192 return DRS(self.refs,
193 [cond.replace(variable, expression, replace_bound, alpha_convert)
194 for cond in self.conds],
195 consequent)
196
198 """@see: Expression.variables()"""
199 conds_vars = reduce(operator.or_,
200 [c.variables() for c in self.conds], set())
201 if self.consequent:
202 conds_vars.update(self.consequent.variables())
203 return conds_vars - set(self.refs)
204
205 - def free(self, indvar_only=True):
206 """@see: Expression.free()"""
207 conds_free = reduce(operator.or_,
208 [c.free(indvar_only) for c in self.conds], set())
209 if self.consequent:
210 conds_free.update(self.consequent.free())
211 return conds_free - set(self.refs)
212
214 """@see: AbstractExpression.get_refs()"""
215 if recursive:
216 conds_refs = self.refs + sum((c.get_refs(True) for c in self.conds), [])
217 if self.consequent:
218 conds_refs.extend(self.consequent.get_refs(True))
219 return conds_refs
220 else:
221 return self.refs
222
223 - def visit(self, function, combinator, default):
224 """@see: Expression.visit()"""
225 parts = self.refs + self.conds
226 if self.consequent:
227 parts.append(self.consequent)
228 return reduce(combinator, map(function, parts), default)
229
231 drs = self
232 i = 0
233 while i < len(drs.conds):
234 cond = drs.conds[i]
235 if isinstance(cond, EqualityExpression) and \
236 isinstance(cond.first, AbstractVariableExpression) and \
237 isinstance(cond.second, AbstractVariableExpression):
238 drs = DRS(list(set(drs.refs)-set([cond.second.variable])),
239 drs.conds[:i]+drs.conds[i+1:],
240 drs.consequent)
241 if cond.second.variable != cond.first.variable:
242 drs = drs.replace(cond.second.variable, cond.first, False, False)
243 i = 0
244 i -= 1
245 i += 1
246
247 conds = []
248 for cond in drs.conds:
249 new_cond = cond.eliminate_equality()
250 new_cond_simp = new_cond.simplify()
251 if not isinstance(new_cond_simp, DRS) or \
252 new_cond_simp.refs or new_cond_simp.conds or \
253 new_cond_simp.consequent:
254 conds.append(new_cond)
255 if drs.consequent:
256 consequent = drs.consequent.eliminate_equality()
257 else:
258 consequent = None
259 return DRS(drs.refs, conds, consequent)
260
262 if self.consequent:
263 consequent = self.consequent.simplify()
264 else:
265 consequent = None
266 return DRS(self.refs,
267 [cond.simplify() for cond in self.conds],
268 consequent)
269
271 if self.consequent:
272 accum = None
273 if self.conds:
274 accum = reduce(AndExpression, [c.fol() for c in self.conds])
275
276 if accum:
277 accum = ImpExpression(accum, self.consequent.fol())
278 else:
279 accum = self.consequent.fol()
280
281 for ref in self.refs[::-1]:
282 accum = AllExpression(ref, accum)
283
284 return accum
285
286 else:
287 if not self.conds:
288 raise Exception("Cannot convert DRS with no conditions to FOL.")
289 accum = reduce(AndExpression, [c.fol() for c in self.conds])
290 for ref in map(Variable, self._order_ref_strings(self.refs)[::-1]):
291 accum = ExistsExpression(ref, accum)
292 return accum
293
307
309 strings = map(str, refs)
310 ind_vars = []
311 func_vars = []
312 event_vars = []
313 other_vars = []
314 for s in strings:
315 if is_indvar(s):
316 ind_vars.append(s)
317 elif is_funcvar(s):
318 func_vars.append(s)
319 elif is_eventvar(s):
320 event_vars.append(s)
321 else:
322 other_vars.append(s)
323 return sorted(other_vars) + \
324 sorted(event_vars, key=lambda v: int([v[2:],-1][len(v[2:]) == 0])) + \
325 sorted(func_vars, key=lambda v: (v[0], int([v[1:],-1][len(v[1:])==0]))) + \
326 sorted(ind_vars, key=lambda v: (v[0], int([v[1:],-1][len(v[1:])==0])))
327
329 r"""Defines equality modulo alphabetic variance.
330 If we are comparing \x.M and \y.N, then check equality of M and N[x/y]."""
331 if isinstance(other, DRS):
332 if len(self.refs) == len(other.refs):
333 converted_other = other
334 for (r1, r2) in zip(self.refs, converted_other.refs):
335 varex = self.make_VariableExpression(r1)
336 converted_other = converted_other.replace(r2, varex, True)
337 if self.consequent == converted_other.consequent and \
338 len(self.conds) == len(converted_other.conds):
339 for c1, c2 in zip(self.conds, converted_other.conds):
340 if not (c1 == c2):
341 return False
342 return True
343 return False
344
352
367
372
374 """@see: AbstractExpression.get_refs()"""
375 return []
376
378 s = str(self)
379 blank = ' '*len(s)
380 return [blank, blank, s, blank]
381
384
387
390
393
397 self.variable = variable
398 self.drs = drs
399
400 - def replace(self, variable, expression, replace_bound=False, alpha_convert=True):
401 if self.variable == variable:
402 assert isinstance(expression, DrtAbstractVariableExpression), "Can only replace a proposition label with a variable"
403 return DrtProposition(expression.variable, self.drs.replace(variable, expression, replace_bound, alpha_convert))
404 else:
405 return DrtProposition(self.variable, self.drs.replace(variable, expression, replace_bound, alpha_convert))
406
409
412
414 if recursive:
415 return self.drs.get_refs(True)
416 else:
417 return []
418
420 return self.__class__ == other.__class__ and \
421 self.variable == other.variable and \
422 self.drs == other.drs
423
425 return self.drs.fol()
426
428 drs_s = self.drs._pretty()
429 blank = ' '*(len(str(self.variable))+1)
430 return [blank + drs_s[0],
431 str(self.variable) + ':' + drs_s[1]] + \
432 map(lambda l: blank+l, drs_s[2:])
433
434 - def visit(self, function, combinator, default):
435 return combinator(function(self.variable), function(self.drs))
436
438 return 'prop(%s, %s)' % (self.variable, self.drs)
439
444
446 """@see: AbstractExpression.get_refs()"""
447 return self.term.get_refs(recursive)
448
450 term_lines = self.term._pretty()
451 return [' ' + line for line in term_lines[:2]] + \
452 ['__ ' + term_lines[2]] + \
453 [' | ' + term_lines[3]] + \
454 [' ' + line for line in term_lines[4:]]
455
458 """Rename all occurrences of the variable introduced by this variable
459 binder in the expression to @C{newvar}.
460 @param newvar: C{Variable}, for the new variable
461 """
462 return self.__class__(newvar, self.term.replace(self.variable,
463 DrtVariableExpression(newvar), True))
464
467
469 variables = [self.variable]
470 term = self.term
471 while term.__class__ == self.__class__:
472 variables.append(term.variable)
473 term = term.term
474 var_string = ' '.join(map(str, variables)) + DrtTokens.DOT
475 term_lines = term._pretty()
476 return [' ' + ' '*len(var_string) + line for line in term_lines[:1]] + \
477 [' \ ' + ' '*len(var_string) + term_lines[1]] + \
478 [' /\ ' + var_string + term_lines[2]] + \
479 [' ' + ' '*len(var_string) + line for line in term_lines[3:]]
480
483 """@see: AbstractExpression.get_refs()"""
484 if recursive:
485 return self.first.get_refs(True) + self.second.get_refs(True)
486 else:
487 return []
488
491
492 @staticmethod
494 max_lines = max(len(first_lines), len(second_lines))
495 first_lines = first_lines + [' '*len(first_lines[0])]*(max_lines-len(first_lines))
496 second_lines = second_lines + [' '*len(second_lines[0])]*(max_lines-len(second_lines))
497 return [' ' + first_line + ' ' + ' '*len(op) + ' ' + second_line + ' ' for first_line, second_line in zip(first_lines, second_lines)[:2]] + \
498 ['(' + first_lines[2] + ' ' + op + ' ' + second_lines[2] + ')'] + \
499 [' ' + first_line + ' ' + ' '*len(op) + ' ' + second_line + ' ' for first_line, second_line in zip(first_lines, second_lines)[3:]]
500
503
506
515
519
521 """DRS of the form '(DRS + DRS)'"""
522 - def __init__(self, first, second, consequent=None):
525
526 - def replace(self, variable, expression, replace_bound=False, alpha_convert=True):
527 """Replace all instances of variable v with expression E in self,
528 where v is free in self."""
529 first = self.first
530 second = self.second
531 consequent = self.consequent
532
533
534 if variable in self.get_refs():
535 if replace_bound:
536 first = first.replace(variable, expression, replace_bound, alpha_convert)
537 second = second.replace(variable, expression, replace_bound, alpha_convert)
538 if consequent:
539 consequent = consequent.replace(variable, expression, replace_bound, alpha_convert)
540 else:
541 if alpha_convert:
542
543 for ref in (set(self.get_refs(True)) & expression.free()):
544 v = DrtVariableExpression(unique_variable(ref))
545 first = first.replace(ref, v, True, alpha_convert)
546 second = second.replace(ref, v, True, alpha_convert)
547 if consequent:
548 consequent = consequent.replace(ref, v, True, alpha_convert)
549
550 first = first.replace(variable, expression, replace_bound, alpha_convert)
551 second = second.replace(variable, expression, replace_bound, alpha_convert)
552 if consequent:
553 consequent = consequent.replace(variable, expression, replace_bound, alpha_convert)
554
555 return self.__class__(first, second, consequent)
556
562
581
583 """@see: AbstractExpression.get_refs()"""
584 refs = self.first.get_refs(recursive) + self.second.get_refs(recursive)
585 if self.consequent and recursive:
586 refs.extend(self.consequent.get_refs(True))
587 return refs
588
591
593 r"""Defines equality modulo alphabetic variance.
594 If we are comparing \x.M and \y.N, then check equality of M and N[x/y]."""
595 if isinstance(other, DrtConcatenation):
596 self_refs = self.get_refs()
597 other_refs = other.get_refs()
598 if len(self_refs) == len(other_refs):
599 converted_other = other
600 for (r1,r2) in zip(self_refs, other_refs):
601 varex = self.make_VariableExpression(r1)
602 converted_other = converted_other.replace(r2, varex, True)
603 return self.first == converted_other.first and \
604 self.second == converted_other.second and \
605 self.consequent == converted_other.consequent
606 return False
607
613
622
627
628
629 - def visit(self, function, combinator, default):
630 """@see: Expression.visit()"""
631 if self.consequent:
632 return combinator(function(self.first), function(self.second), function(self.consequent))
633 else:
634 return combinator(function(self.first), function(self.second))
635
645
647 s = str(subex)
648 if isinstance(subex, DrtConcatenation) and subex.consequent is None:
649 return s[1:-1]
650 return s
651
656
658 """@see: AbstractExpression.get_refs()"""
659 if recursive:
660 return self.function.get_refs(True) + self.argument.get_refs(True)
661 else:
662 return []
663
665 function, args = self.uncurry()
666 function_lines = function._pretty()
667 args_lines = [arg._pretty() for arg in args]
668 max_lines = max(map(len, [function_lines] + args_lines))
669 function_lines = function_lines + [' '*len(function_lines[0])]*(max_lines-len(function_lines))
670 args_lines = [arg_lines + [' '*len(arg_lines[0])]*(max_lines-len(arg_lines)) for arg_lines in args_lines]
671 return [func_line + ' ' + ' '.join(args_line) + ' ' for func_line, args_line in zip(function_lines, zip(*args_lines))[:2]] + \
672 [function_lines[2] + '(' + ','.join(zip(*args_lines)[2]) + ')'] + \
673 [func_line + ' ' + ' '.join(args_line) + ' ' for func_line, args_line in zip(function_lines, zip(*args_lines))[3:]]
674
676 - def free(self, indvar_only=True):
677 """Set of free variables."""
678 return set(self)
679
680 - def replace(self, variable, expression, replace_bound=False, alpha_convert=True):
681 """Replace all instances of variable v with expression E in self,
682 where v is free in self."""
683 result = PossibleAntecedents()
684 for item in self:
685 if item == variable:
686 self.append(expression)
687 else:
688 self.append(item)
689 return result
690
692 s = str(self)
693 blank = ' '*len(s)
694 return [blank,blank,s]
695
697 return '[' + ','.join(map(str, self)) + ']'
698
702
705 if isinstance(expression, ApplicationExpression):
706 if expression.is_pronoun_function():
707 possible_antecedents = PossibleAntecedents()
708 for ancestor in trail:
709 for ref in ancestor.get_refs():
710 refex = expression.make_VariableExpression(ref)
711
712
713
714
715 if refex.__class__ == expression.argument.__class__ and \
716 not (refex == expression.argument):
717 possible_antecedents.append(refex)
718
719 if len(possible_antecedents) == 1:
720 resolution = possible_antecedents[0]
721 else:
722 resolution = possible_antecedents
723 return expression.make_EqualityExpression(expression.argument, resolution)
724 else:
725 r_function = resolve_anaphora(expression.function, trail + [expression])
726 r_argument = resolve_anaphora(expression.argument, trail + [expression])
727 return expression.__class__(r_function, r_argument)
728
729 elif isinstance(expression, DRS):
730 r_conds = []
731 for cond in expression.conds:
732 r_cond = resolve_anaphora(cond, trail + [expression])
733
734
735 if isinstance(r_cond, EqualityExpression):
736 if isinstance(r_cond.first, PossibleAntecedents):
737
738 temp = r_cond.first
739 r_cond.first = r_cond.second
740 r_cond.second = temp
741 if isinstance(r_cond.second, PossibleAntecedents):
742 if not r_cond.second:
743 raise AnaphoraResolutionException("Variable '%s' does not "
744 "resolve to anything." % r_cond.first)
745
746 r_conds.append(r_cond)
747 if expression.consequent:
748 consequent = resolve_anaphora(expression.consequent, trail + [expression])
749 else:
750 consequent = None
751 return expression.__class__(expression.refs, r_conds, consequent)
752
753 elif isinstance(expression, AbstractVariableExpression):
754 return expression
755
756 elif isinstance(expression, NegatedExpression):
757 return expression.__class__(resolve_anaphora(expression.term, trail + [expression]))
758
759 elif isinstance(expression, DrtConcatenation):
760 if expression.consequent:
761 consequent = resolve_anaphora(expression.consequent, trail + [expression])
762 else:
763 consequent = None
764 return expression.__class__(resolve_anaphora(expression.first, trail + [expression]),
765 resolve_anaphora(expression.second, trail + [expression]),
766 consequent)
767
768 elif isinstance(expression, BinaryExpression):
769 return expression.__class__(resolve_anaphora(expression.first, trail + [expression]),
770 resolve_anaphora(expression.second, trail + [expression]))
771
772 elif isinstance(expression, LambdaExpression):
773 return expression.__class__(expression.variable, resolve_anaphora(expression.term, trail + [expression]))
774
777 BUFFER = 3
778 TOPSPACE = 10
779 OUTERSPACE = 6
780
781 - def __init__(self, drs, size_canvas=True, canvas=None):
782 """
783 @param drs: C{AbstractDrs}, The DRS to be drawn
784 @param size_canvas: C{boolean}, True if the canvas size should be the exact size of the DRS
785 @param canvas: C{Canvas} The canvas on which to draw the DRS. If none is given, create a new canvas.
786 """
787 master = None
788 if not canvas:
789 master = Tk()
790 master.title("DRT")
791
792 font = Font(family='helvetica', size=12)
793
794 if size_canvas:
795 canvas = Canvas(master, width=0, height=0)
796 canvas.font = font
797 self.canvas = canvas
798 (right, bottom) = self._visit(drs, self.OUTERSPACE, self.TOPSPACE)
799
800 width = max(right+self.OUTERSPACE, 100)
801 height = bottom+self.OUTERSPACE
802 canvas = Canvas(master, width=width, height=height)
803 else:
804 canvas = Canvas(master, width=300, height=300)
805
806 canvas.pack()
807 canvas.font = font
808
809 self.canvas = canvas
810 self.drs = drs
811 self.master = master
812
814 """Get the height of a line of text"""
815 return self.canvas.font.metrics("linespace")
816
825
826 - def _visit(self, expression, x, y):
827 """
828 Return the bottom-rightmost point without actually drawing the item
829
830 @param expression: the item to visit
831 @param x: the top of the current drawing area
832 @param y: the left side of the current drawing area
833 @return: the bottom-rightmost point
834 """
835 return self._handle(expression, self._visit_command, x, y)
836
838 """
839 Draw the given item at the given location
840
841 @param item: the item to draw
842 @param x: the top of the current drawing area
843 @param y: the left side of the current drawing area
844 @return: the bottom-rightmost point
845 """
846 if isinstance(item, str):
847 self.canvas.create_text(x, y, anchor='nw', font=self.canvas.font, text=item)
848 elif isinstance(item, tuple):
849
850 (right, bottom) = item
851 self.canvas.create_rectangle(x, y, right, bottom)
852 horiz_line_y = y + self._get_text_height() + (self.BUFFER * 2)
853 self.canvas.create_line(x, horiz_line_y, right, horiz_line_y)
854
855 return self._visit_command(item, x, y)
856
858 """
859 Return the bottom-rightmost point without actually drawing the item
860
861 @param item: the item to visit
862 @param x: the top of the current drawing area
863 @param y: the left side of the current drawing area
864 @return: the bottom-rightmost point
865 """
866 if isinstance(item, str):
867 return (x + self.canvas.font.measure(item), y + self._get_text_height())
868 elif isinstance(item, tuple):
869 return item
870
871 - def _handle(self, expression, command, x=0, y=0):
872 """
873 @param expression: the expression to handle
874 @param command: the function to apply, either _draw_command or _visit_command
875 @param x: the top of the current drawing area
876 @param y: the left side of the current drawing area
877 @return: the bottom-rightmost point
878 """
879 if command == self._visit_command:
880
881 try:
882
883 right = expression._drawing_width + x
884 bottom = expression._drawing_height + y
885 return (right, bottom)
886 except AttributeError:
887
888 pass
889
890 if isinstance(expression, DrtAbstractVariableExpression):
891 factory = self._handle_VariableExpression
892 elif isinstance(expression, DRS):
893 factory = self._handle_DRS
894 elif isinstance(expression, DrtNegatedExpression):
895 factory = self._handle_NegatedExpression
896 elif isinstance(expression, DrtLambdaExpression):
897 factory = self._handle_LambdaExpression
898 elif isinstance(expression, BinaryExpression):
899 factory = self._handle_BinaryExpression
900 elif isinstance(expression, DrtApplicationExpression):
901 factory = self._handle_ApplicationExpression
902 elif isinstance(expression, PossibleAntecedents):
903 factory = self._handle_VariableExpression
904 elif isinstance(expression, DrtProposition):
905 factory = self._handle_DrtProposition
906 else:
907 raise Exception, expression.__class__.__name__
908
909 (right, bottom) = factory(expression, command, x, y)
910
911
912 expression._drawing_width = right - x
913 expression._drawing_height = bottom - y
914
915 return (right, bottom)
916
918 return command(str(expression), x, y)
919
921
922 right = self._visit_command(DrtTokens.NOT, x, y)[0]
923
924
925 (right, bottom) = self._handle(expression.term, command, right, y)
926
927
928 command(DrtTokens.NOT, x, self._get_centered_top(y, bottom - y, self._get_text_height()))
929
930 return (right, bottom)
931
933 left = x + self.BUFFER
934 bottom = y + self.BUFFER
935
936
937 if expression.refs:
938 refs = ' '.join(map(str, expression.refs))
939 else:
940 refs = ' '
941 (max_right, bottom) = command(refs, left, bottom)
942 bottom += (self.BUFFER * 2)
943
944
945 if expression.conds:
946 for cond in expression.conds:
947 (right, bottom) = self._handle(cond, command, left, bottom)
948 max_right = max(max_right, right)
949 bottom += self.BUFFER
950 else:
951 bottom += self._get_text_height() + self.BUFFER
952
953
954 max_right += self.BUFFER
955 return command((max_right, bottom), x, y)
956
958 function, args = expression.uncurry()
959 if not isinstance(function, DrtAbstractVariableExpression):
960
961 function = expression.function
962 args = [expression.argument]
963
964
965 function_bottom = self._visit(function, x, y)[1]
966 max_bottom = max([function_bottom] + [self._visit(arg, x, y)[1] for arg in args])
967
968 line_height = max_bottom - y
969
970
971 function_drawing_top = self._get_centered_top(y, line_height, function._drawing_height)
972 right = self._handle(function, command, x, function_drawing_top)[0]
973
974
975 centred_string_top = self._get_centered_top(y, line_height, self._get_text_height())
976 right = command(DrtTokens.OPEN, right, centred_string_top)[0]
977
978
979 for (i,arg) in enumerate(args):
980 arg_drawing_top = self._get_centered_top(y, line_height, arg._drawing_height)
981 right = self._handle(arg, command, right, arg_drawing_top)[0]
982
983 if i+1 < len(args):
984
985 right = command(DrtTokens.COMMA + ' ', right, centred_string_top)[0]
986
987
988 right = command(DrtTokens.CLOSE, right, centred_string_top)[0]
989
990 return (right, max_bottom)
991
993
994 variables = DrtTokens.LAMBDA + str(expression.variable) + DrtTokens.DOT
995 right = self._visit_command(variables, x, y)[0]
996
997
998 (right, bottom) = self._handle(expression.term, command, right, y)
999
1000
1001 command(variables, x, self._get_centered_top(y, bottom - y, self._get_text_height()))
1002
1003 return (right, bottom)
1004
1006
1007 first_height = self._visit(expression.first, 0, 0)[1]
1008 second_height = self._visit(expression.second, 0, 0)[1]
1009 line_height = max(first_height, second_height)
1010
1011
1012 centred_string_top = self._get_centered_top(y, line_height, self._get_text_height())
1013 right = command(DrtTokens.OPEN, x, centred_string_top)[0]
1014
1015
1016 first_height = expression.first._drawing_height
1017 (right, first_bottom) = self._handle(expression.first, command, right, self._get_centered_top(y, line_height, first_height))
1018
1019
1020 right = command(' %s ' % expression.getOp(), right, centred_string_top)[0]
1021
1022
1023 second_height = expression.second._drawing_height
1024 (right, second_bottom) = self._handle(expression.second, command, right, self._get_centered_top(y, line_height, second_height))
1025
1026
1027 right = command(DrtTokens.CLOSE, right, centred_string_top)[0]
1028
1029 return (right, max(first_bottom, second_bottom))
1030
1032
1033 right = command(expression.variable, x, y)[0]
1034
1035
1036 (right, bottom) = self._handle(expression.term, command, right, y)
1037
1038 return (right, bottom)
1039
1041 """Get the y-coordinate of the point that a figure should start at if
1042 its height is 'item_height' and it needs to be centered in an area that
1043 starts at 'top' and is 'full_height' tall."""
1044 return top + (full_height - item_height) / 2
1045
1048 """A lambda calculus expression parser."""
1061
1065
1068
1069 - def handle(self, tok, context):
1090
1093
1102
1113
1124
1126 """This method serves as a hook for other logic parsers that
1127 have different equality expression classes"""
1128 return DrtEqualityExpression(first, second)
1129
1131 """This method serves as a hook for other logic parsers that
1132 have different boolean operators"""
1133 if tok == DrtTokens.DRS_CONC:
1134 return lambda first, second: DrtConcatenation(first, second, None)
1135 elif tok in DrtTokens.OR_LIST:
1136 return DrtOrExpression
1137 elif tok in DrtTokens.IMP_LIST:
1138 def make_imp_expression(first, second):
1139 if isinstance(first, DRS):
1140 return DRS(first.refs, first.conds, second)
1141 if isinstance(first, DrtConcatenation):
1142 return DrtConcatenation(first.first, first.second, second)
1143 raise Exception('Antecedent of implication must be a DRS')
1144 return make_imp_expression
1145 else:
1146 return None
1147
1150
1153
1156
1159
1162 print '='*20 + 'TEST PARSE' + '='*20
1163 parser = DrtParser()
1164 print parser.parse(r'([x,y],[sees(x,y)])')
1165 print parser.parse(r'([x],[man(x), walks(x)])')
1166 print parser.parse(r'\x.\y.([],[sees(x,y)])')
1167 print parser.parse(r'\x.([],[walks(x)])(john)')
1168 print parser.parse(r'(([x],[walks(x)]) + ([y],[runs(y)]))')
1169 print parser.parse(r'(([],[walks(x)]) -> ([],[runs(x)]))')
1170 print parser.parse(r'([x],[PRO(x), sees(John,x)])')
1171 print parser.parse(r'([x],[man(x), -([],[walks(x)])])')
1172 print parser.parse(r'([],[(([x],[man(x)]) -> ([],[walks(x)]))])')
1173
1174 print '='*20 + 'Test fol()' + '='*20
1175 print parser.parse(r'([x,y],[sees(x,y)])').fol()
1176
1177 print '='*20 + 'Test alpha conversion and lambda expression equality' + '='*20
1178 e1 = parser.parse(r'\x.([],[P(x)])')
1179 print e1
1180 e2 = e1.alpha_convert(Variable('z'))
1181 print e2
1182 print e1 == e2
1183
1184 print '='*20 + 'Test resolve_anaphora()' + '='*20
1185 print resolve_anaphora(parser.parse(r'([x,y,z],[dog(x), cat(y), walks(z), PRO(z)])'))
1186 print resolve_anaphora(parser.parse(r'([],[(([x],[dog(x)]) -> ([y],[walks(y), PRO(y)]))])'))
1187 print resolve_anaphora(parser.parse(r'(([x,y],[]) + ([],[PRO(x)]))'))
1188
1189 print '='*20 + 'Test pprint()' + '='*20
1190 parser.parse(r"([],[])").pprint()
1191 parser.parse(r"([],[([x],[big(x), dog(x)]) -> ([],[bark(x)]) -([x],[walk(x)])])").pprint()
1192 parser.parse(r"([x,y],[x=y]) + ([z],[dog(z), walk(z)])").pprint()
1193 parser.parse(r"([],[([x],[]) | ([y],[]) | ([z],[dog(z), walk(z)])])").pprint()
1194 parser.parse(r"\P.\Q.(([x],[]) + P(x) + Q(x))(\x.([],[dog(x)]))").pprint()
1195
1198 expressions = [
1199 r'x',
1200 r'([],[])',
1201 r'([x],[])',
1202 r'([x],[man(x)])',
1203
1204 r'([x,y],[sees(x,y)])',
1205 r'([x],[man(x), walks(x)])',
1206 r'\x.([],[man(x), walks(x)])',
1207 r'\x y.([],[sees(x,y)])',
1208 r'([],[(([],[walks(x)]) + ([],[runs(x)]))])',
1209
1210 r'([x],[man(x), -([],[walks(x)])])',
1211 r'([],[(([x],[man(x)]) -> ([],[walks(x)]))])'
1212 ]
1213
1214 for e in expressions:
1215 d = DrtParser().parse(e)
1216 d.draw()
1217
1218
1219 if __name__ == '__main__':
1220 demo()
1221