Package jazzparser :: Package evaluation :: Module parsing
[hide private]
[frames] | no frames]

Source Code for Module jazzparser.evaluation.parsing

  1  """Evaluation tools for evaluating the parsing process. 
  2   
  3  Once upon a time, this was a handy interface to  
  4  supertagging and parsing that made it easy to write evaluation routines.  
  5  Nowadays, the main parse script is much more capable and the interface  
  6  to the parsers is much cleaner anyway. 
  7   
  8  The only thing left here now is C{parse_sequence_with_annotations}  
  9   
 10  """ 
 11  """ 
 12  ============================== License ======================================== 
 13   Copyright (C) 2008, 2010-12 University of Edinburgh, Mark Granroth-Wilding 
 14    
 15   This file is part of The Jazz Parser. 
 16    
 17   The Jazz Parser is free software: you can redistribute it and/or modify 
 18   it under the terms of the GNU General Public License as published by 
 19   the Free Software Foundation, either version 3 of the License, or 
 20   (at your option) any later version. 
 21    
 22   The Jazz Parser is distributed in the hope that it will be useful, 
 23   but WITHOUT ANY WARRANTY; without even the implied warranty of 
 24   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 25   GNU General Public License for more details. 
 26    
 27   You should have received a copy of the GNU General Public License 
 28   along with The Jazz Parser.  If not, see <http://www.gnu.org/licenses/>. 
 29   
 30  ============================ End license ====================================== 
 31   
 32  """ 
 33  __author__ = "Mark Granroth-Wilding <mark.granroth-wilding@ed.ac.uk>"  
 34   
 35  import sys, traceback, os 
 36   
 37  from jazzparser.data.trees import build_tree_for_sequence, TreeBuildError 
 38  from jazzparser.parsers.cky.parser import DirectedCkyParser, DirectedParseError 
 39  from jazzparser.data.input import DbInput, AnnotatedDbInput 
 40  from jazzparser.taggers.pretagged import PretaggedTagger 
 41  from jazzparser.parsers import ParseError 
 42  from jazzparser.grammar import get_grammar 
 43  from jazzparser.data.db_mirrors import SequenceIndex 
 44  from jazzparser.data.parsing import ParseResults 
 45  from jazzparser.utils.loggers import create_logger, create_dummy_logger 
 46   
47 -def parse_sequence_with_annotations(sequence, grammar, logger=None, 48 allow_subparses=True, popts={}, parse_logger=None):
49 """ 50 Parses an annotated sequence. This is essentially just constructing 51 the implicit derivation encoded in the annotations (categories 52 and coordination markers) and returning the top-level result that 53 this derivation yields. 54 55 If there are missing annotations, this will not yield a single 56 result, but the results of each parse of a subsequence. 57 58 Returns a list of parse results. If the annotation is complete, the 59 return value should be a single-item list containing the parse 60 result. 61 62 @type allow_subparses: boolean 63 @param allow_subparses: if True (default) will return multiple 64 subparses if the annotation is incomplete. If False, raises 65 a ParseError in this case. 66 @type popts: dict 67 @param popts: options to pass to the parser 68 @type parse_logger: bool 69 @param parse_logger: logger to which to report a trace of the shift-reduce 70 parse of the annotations. If None, nothing is output 71 72 """ 73 # Prepare the input and annotations 74 if isinstance(sequence, DbInput): 75 input = sequence 76 sequence = sequence.sequence 77 durations = input.durations 78 times = input.times 79 else: 80 raise ValueError, "parse_sequence_with_annotations can only be "\ 81 "applied to a DbInput. Got: %s" % type(sequence).__name__ 82 categories = [chord.category for chord in sequence.iterator()] 83 84 try: 85 tree = build_tree_for_sequence(sequence, grammar=grammar) 86 except TreeBuildError, err: 87 raise ParseError, "could not build a tree for '%s': %s" % \ 88 (sequence.string_name, err) 89 90 if not allow_subparses and len(tree.children) > 1: 91 raise ParseError, "gold standard for sequence '%s' does not "\ 92 "yield a single tree: annotation is incomplete" % \ 93 sequence.string_name 94 95 sub_parses = [] 96 end = 0 97 i = 0 98 # Each subtree of the root represents a partial parse 99 for sub_tree in tree.children: 100 # Use each partial tree to get counts 101 length = sub_tree.span_length 102 start = end 103 end += length 104 105 # If this is just a leaf: ignore it - it came from an unlabelled chord 106 if hasattr(sub_tree, 'chord'): 107 continue 108 i += 1 109 110 # Prepare the tagger for this part of the sequence. 111 # Get a sign for each annotated chord 112 tags = [] 113 for word,tag,duration,time in zip( 114 list(input)[start:end], 115 categories[start:end], 116 durations[start:end], 117 times[start:end]): 118 if tag == "": 119 word_signs = [] 120 elif tag not in grammar.families: 121 raise ParseError, "could not get a sign from the "\ 122 "grammar for the tag %s (chord %s)" % \ 123 (tag, word) 124 else: 125 # Get all signs that correspond to this tag from the grammar 126 word_signs = grammar.get_signs_for_word(word, tags=[tag], 127 extra_features={ 128 'duration' : duration, 129 'time' : time, 130 }) 131 tags.append(word_signs) 132 tagger = PretaggedTagger(grammar, input.slice(start,end), tags=tags) 133 134 # Use the directed parser to try parsing according to this tree 135 parser = DirectedCkyParser(grammar, tagger, derivation_tree=sub_tree, options=popts) 136 try: 137 parser.parse(derivations=True) 138 except DirectedParseError, err: 139 # Parse failed, so we can't train on this sequence 140 raise ParseError, "[Partial parse %d (%d-%d)] parsing using "\ 141 "the derivation tree failed: %s" % (i,start,end,err) 142 # We should now have a complete parse available 143 parses = parser.chart.parses 144 if len(parses) == 0: 145 raise ParseError, "[Partial parse %d (%d-%d)] parsing using the "\ 146 "derivation tree did not produce any results" % (i,start,end) 147 elif len(parses) > 1: 148 raise ParseError, "the annotated tree gave multiple "\ 149 "parse results: %s" % ", ".join(["%s" % p for p in parses]) 150 else: 151 sub_parses.append(parses[0]) 152 153 return sub_parses
154