JL ipdZddlZddlZddlZddlmZddlmZmZm Z ddl m Z ddl m Z ddlmZddlmZeGd d ZGd d eZGd deZGddZGddZGddeZGddeZGddeZGddeZGddeZGddeZGdd eZGd!d"eZGd#d$eZGd%d&eZ Gd'd(eZ!Gd)d*eZ"d;d+Z#eeeegZ$ee eegZ%ee eegZ&ee"e!gZ'Gd,d-e Z(Gd.d/e(Z)Gd0d1e(Z*Gd2d3e(Z+Gd4d5e(Z,Gd6d7e(Z-d8Z. d>U ";< < #ct)z Return a tuple ``(s, e)``, where ``tokens[s:e]`` is the portion of the sentence that is consistent with this edge's structure. :rtype: tuple(int, int) NotImplementedErrorrs rspanz EdgeI.span` "##rct)zR Return the start index of this edge's span. :rtype: int rrs rstartz EdgeI.startj "##rct)zP Return the end index of this edge's span. :rtype: int rrs rendz EdgeI.endrrrct)zM Return the length of this edge's span. :rtype: int rrs rlengthz EdgeI.lengthzrrct)z Return this edge's left-hand side, which specifies what kind of structure is hypothesized by this edge. :see: ``TreeEdge`` and ``LeafEdge`` for a description of the left-hand side values for each edge type. rrs rlhsz EdgeI.lhsrrct)a Return this edge's right-hand side, which specifies the content of the structure hypothesized by this edge. :see: ``TreeEdge`` and ``LeafEdge`` for a description of the right-hand side values for each edge type. rrs rrhsz EdgeI.rhsrrct)a Return this edge's dot position, which indicates how much of the hypothesized structure is consistent with the sentence. In particular, ``self.rhs[:dot]`` is consistent with ``tokens[self.start():self.end()]``. :rtype: int rrs rdotz EdgeI.dot "##rct)z Return the element of this edge's right-hand side that immediately follows its dot. :rtype: Nonterminal or terminal or None rrs rnextsymz EdgeI.nextsym "##rct)zw Return True if this edge's structure is fully consistent with the text. :rtype: bool rrs r is_completezEdgeI.is_completer*rct)z{ Return True if this edge's structure is partially consistent with the text. :rtype: bool rrs r is_incompletezEdgeI.is_incompleter*rch|j|juxr|j|jk(SN)r_comparison_keyrothers r__eq__z EdgeI.__eq__s0 NNeoo - >$$(=(== rc||k( Sr0r2s r__ne__z EdgeI.__ne__s5=  rct|ts td|||j|jur|j|jkS|jj |jj kS)N<) isinstancer rrr1__name__r2s r__lt__z EdgeI.__lt__s^%' #Cu 5 >>U__ ,''%*?*?? ?>>**U__-E-EE Erc |jS#t$r)t|j|_|jcYSwxYwr0)_hashAttributeErrorhashr1rs r__hash__zEdgeI.__hash__s< ::  d223DJ::  s /AAN)r; __module__ __qualname____doc__rrrrr r"r$r&r)r,r.r4r7r<rAr6rrr r 6sT@=$$$$$$ $$$$ !Frr cveZdZdZddZedZdZdZdZ dZ dZ d Z d Z d Zd Zd ZdZdZdZy)TreeEdgea An edge that records the fact that a tree is (partially) consistent with the sentence. A tree edge consists of: - A span, indicating what part of the sentence is consistent with the hypothesized tree. - A left-hand side, specifying the hypothesized tree's node value. - A right-hand side, specifying the hypothesized tree's children. Each element of the right-hand side is either a terminal, specifying a token with that terminal as its leaf value; or a nonterminal, specifying a subtree with that nonterminal's symbol as its node value. - A dot position, indicating which children are consistent with part of the sentence. In particular, if ``dot`` is the dot position, ``rhs`` is the right-hand size, ``(start,end)`` is the span, and ``sentence`` is the list of tokens in the sentence, then ``tokens[start:end]`` can be spanned by the children specified by ``rhs[:dot]``. For more information about edges, see the ``EdgeI`` interface. ch||_||_t|}||_||_||||f|_y)a Construct a new ``TreeEdge``. :type span: tuple(int, int) :param span: A tuple ``(s, e)``, where ``tokens[s:e]`` is the portion of the sentence that is consistent with the new edge's structure. :type lhs: Nonterminal :param lhs: The new edge's left-hand side, specifying the hypothesized tree's node value. :type rhs: list(Nonterminal and str) :param rhs: The new edge's right-hand side, specifying the hypothesized tree's children. :type dot: int :param dot: The position of the new edge's dot. This position specifies what prefix of the production's right hand side is consistent with the text. In particular, if ``sentence`` is the list of tokens in the sentence, then ``okens[span[0]:span[1]]`` can be spanned by the children specified by ``rhs[:dot]``. N)_span_lhstuple_rhs_dotr1)rrr"r$r&s rrzTreeEdge.__init__s:,  Cj  $c34rc\t||f|j|jdS)a Return a new ``TreeEdge`` formed from the given production. The new edge's left-hand side and right-hand side will be taken from ``production``; its span will be ``(index,index)``; and its dot position will be ``0``. :rtype: TreeEdge rrr"r$r&)rFr"r$) productionindexs rfrom_productionzTreeEdge.from_productions-Z^^%5:>>;KQR  rct|jd|f|j|j|jdzS)a Return a new ``TreeEdge`` formed from this edge. The new edge's dot position is increased by ``1``, and its end index will be replaced by ``new_end``. :param new_end: The new end index. :type new_end: int :rtype: TreeEdge rrN)rFrHrIrKrL)rnew_ends rmove_dot_forwardzTreeEdge.move_dot_forward$s:**Q-)   A   rc|jSr0)rIrs rr"z TreeEdge.lhs6 yyrc|jSr0rHrs rrz TreeEdge.span9 zzrc |jdSNrrYrs rrzTreeEdge.start<zz!}rc |jdSNrSrYrs rrz TreeEdge.end?r]rc@|jd|jdz S)NrSrrYrs rr zTreeEdge.lengthBszz!}tzz!},,rc|jSr0)rKrs rr$z TreeEdge.rhsErWrc|jSr0)rLrs rr&z TreeEdge.dotHrWrcF|jt|jk(Sr0rLlenrKrs rr,zTreeEdge.is_completeKyyC N**rcF|jt|jk7Sr0rdrs rr.zTreeEdge.is_incompleteNrfrcz|jt|jk\ry|j|jSr0rdrs rr)zTreeEdge.nextsymQs, 99DII &99TYY' 'rcjd|jdd|jdd}||jddz }tt|jD]4}||j k(r|dz }|d t |j|zz }6t|j|j k(r|dz }|S) N[r:rS] 2z ->z *z %s)rHrIrangererKrLrepr)rstris r__str__zTreeEdge.__str__Xs$**Q-$**Q-3 DII''s499~& .ADII~t  54 ! -- -C . tyy>TYY & 4KC rc d|zSNz [Edge: %s]r6rs r__repr__zTreeEdge.__repr__ds d""rNr)r;rBrCrDr staticmethodrQrUr"rrrr r$r&r,r.r)rrrur6rrrFrFsa.5:     $-++( #rrFc^eZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZy)LeafEdgea An edge that records the fact that a leaf value is consistent with a word in the sentence. A leaf edge consists of: - An index, indicating the position of the word. - A leaf, specifying the word's content. A leaf edge's left-hand side is its leaf value, and its right hand side is ``()``. Its span is ``[index, index+1]``, and its dot position is ``0``. c2||_||_||f|_y)a Construct a new ``LeafEdge``. :param leaf: The new edge's leaf value, specifying the word that is recorded by this edge. :param index: The new edge's index, specifying the position of the word that is recorded by this edge. N)_leaf_indexr1)rleafrPs rrzLeafEdge.__init__us  $e}rc|jSr0)r{rs rr"z LeafEdge.lhsrZrc8|j|jdzfSr_r|rs rrz LeafEdge.spans T[[1_--rc|jSr0rrs rrzLeafEdge.starts {{rc |jdzSr_rrs rrz LeafEdge.ends{{Qrcyr_r6rs rr zLeafEdge.lengthrcyNr6r6rs rr$z LeafEdge.rhssrcyr\r6rs rr&z LeafEdge.dotrrcy)NTr6rs rr,zLeafEdge.is_completercyNFr6rs rr.zLeafEdge.is_incompletesrcyr0r6rs rr)zLeafEdge.nextsymrrcld|jd|jdzdt|jS)NrjrkrSrl)r|ror{rs rrrzLeafEdge.__str__s24;;-qq 1D4D3EFFrc d|zSrtr6rs rruzLeafEdge.__repr__s t$$rN)r;rBrCrDrr"rrrr r$r&r,r.r)rrrur6rrryryhsI  -.G%rryceZdZdZdZdZdZdZdZdZ dZ e Z d Z d Z d Zd Zd ZdZdZefdZedfdZdZdZddZddZddZdZy)Charta A blackboard for hypotheses about the syntactic constituents of a sentence. A chart contains a set of edges, and each edge encodes a single hypothesis about the structure of some portion of the sentence. The ``select`` method can be used to select a specific collection of edges. For example ``chart.select(is_complete=True, start=0)`` yields all complete edges whose start indices are 0. To ensure the efficiency of these selection operations, ``Chart`` dynamically creates and maintains an index for each set of attributes that have been selected on. In order to reconstruct the trees that are represented by an edge, the chart associates each edge with a set of child pointer lists. A child pointer list is a list of the edges that license an edge's right-hand side. :ivar _tokens: The sentence that the chart covers. :ivar _num_leaves: The number of tokens. :ivar _edges: A list of the edges in the chart :ivar _edge_to_cpls: A dictionary mapping each edge to a set of child pointer lists that are associated with that edge. :ivar _indexes: A dictionary mapping tuples of edge attributes to indices, where each index maps the corresponding edge attribute values to lists of edges. cxt||_t|j|_|j y)z Construct a new chart. The chart is initialized with the leaf edges corresponding to the terminal leaves. :type tokens: list :param tokens: The sentence that this chart will be used to parse. N)rJ_tokensre _num_leaves initializertokenss rrzChart.__init__s,V} t||, rc.g|_i|_i|_y)z" Clear the chart. N)_edges _edge_to_cpls_indexesrs rrzChart.initializes    rc|jS)z[ Return the number of words in this chart's sentence. :rtype: int )rrs r num_leaveszChart.num_leavess rc |j|S)z\ Return the leaf value of the word at the given index. :rtype: str r)rrPs rr}z Chart.leafs ||E""rc|jS)z{ Return a list of the leaf values of each word in the chart's sentence. :rtype: list(str) rrs rleavesz Chart.leavess||rc |jddS)z Return a list of all edges in this chart. New edges that are added to the chart after the call to edges() will *not* be contained in this list. :rtype: list(EdgeI) :see: ``iteredges``, ``select`` N)rrs redgesz Chart.edges s{{1~rc,t|jS)a Return an iterator over the edges in this chart. It is not guaranteed that new edges which are added to the chart before the iterator is exhausted will also be generated. :rtype: iter(EdgeI) :see: ``edges``, ``select`` )iterrrs r iteredgeszChart.iteredgessDKK  rc,t|jS)zZ Return the number of edges contained in this chart. :rtype: int )rerrs r num_edgeszChart.num_edges"s 4%%&&rc 6ik(rt|jStj}t |}||j vr|j |t fd|D}t|j |j|gS)a` Return an iterator over the edges in this chart. Any new edges that are added to the chart before the iterator is exahusted will also be generated. ``restrictions`` can be used to restrict the set of edges that will be generated. :param span: Only generate edges ``e`` where ``e.span()==span`` :param start: Only generate edges ``e`` where ``e.start()==start`` :param end: Only generate edges ``e`` where ``e.end()==end`` :param length: Only generate edges ``e`` where ``e.length()==length`` :param lhs: Only generate edges ``e`` where ``e.lhs()==lhs`` :param rhs: Only generate edges ``e`` where ``e.rhs()==rhs`` :param nextsym: Only generate edges ``e`` where ``e.nextsym()==nextsym`` :param dot: Only generate edges ``e`` where ``e.dot()==dot`` :param is_complete: Only generate edges ``e`` where ``e.is_complete()==is_complete`` :param is_incomplete: Only generate edges ``e`` where ``e.is_incomplete()==is_incomplete`` :rtype: iter(EdgeI) c3(K|] }| ywr0r6).0key restrictionss r zChart.select..Ms=3\#&=s)rrsortedkeysrJr _add_indexget)rr restr_keysvalss ` rselectz Chart.select*s0 2  $ $L--/0 :&  T]] * OOJ '=*==DMM*-11$;<._D#+s+-DN)hasattrr ValueErrorrrrJ setdefaultappend)rrrrPrrs @rrzChart._add_indexPs  >C5#& !6!<== > -/. j)KK 4DDDDD   T2 & - -d 3 4rc|jjD]:\}}tfd|D}|j|gj <y)zs A helper function for ``insert``, which registers the new edge with all existing indexes. c3@K|]}t|ywr0rrs rrz/Chart._register_with_indexes..hrrN)ritemsrJrr)rrrrPrs ` r_register_with_indexeszChart._register_with_indexesbsQ "&!4!4!6 4 JDDDD   T2 & - -d 3 4rcz|j|}|Dcgc]}||fz }}|j|g|Scc}w)zT Add a new edge to the chart, using a pointer to the previous edge. )child_pointer_listsinsert)rnew_edge previous_edge child_edgecplscplnew_cplss rinsert_with_backpointerzChart.insert_with_backpointerosI'' 6378CC:-'88t{{8/h//9s 8c||jvr"|j||j||jj|t }d}|D]}t |}||vsd||<d}|S)a Add a new edge to the chart, and return True if this operation modified the chart. In particular, return true iff the chart did not already contain ``edge``, or if it did not already associate ``child_pointer_lists`` with ``edge``. :type edge: EdgeI :param edge: The new edge :type child_pointer_lists: sequence of tuple(EdgeI) :param child_pointer_lists: A sequence of lists of the edges that were used to form this edge. This list is used to reconstruct the trees (or partial trees) that are associated with ``edge``. :rtype: bool FT)r _append_edgerrr rJ)rrrrchart_was_modifiedchild_pointer_lists rrz Chart.insertws t)) )   d #  ' ' -!!,,T;=A""5 * !&'9!: !-+/'(%)"  * "!rc:|jj|yr0)rrrrs rrzChart._append_edges 4 rc#K|jd|j|D]}|j||dEd{ y7w)z Return an iterator of the complete tree structures that span the entire chart, and whose root node is ``root``. r)rrr"T) tree_classcompleteN)rrtrees)rrootrrs rparsesz Chart.parsessI KKaT-=-=4KH NDzz$:zM M M N Ms9AAAFc>t|j||i|S)a, Return an iterator of the tree structures that are associated with ``edge``. If ``edge`` is incomplete, then the unexpanded children will be encoded as childless subtrees, whose node value is the corresponding terminal or nonterminal. :rtype: list(Tree) :note: If two trees share a common subtree, then the same Tree may be used to encode that subtree in both trees. If you need to eliminate this subtree sharing, then create a deep copy of each tree. )memor)r_trees)rrrrs rrz Chart.treess DKKhRJKOPPrc ||vr||S|r|jrgSt|tr&|j|j }|g||<|gSg||<g}|j j }|j|D]R}|D cgc]} |j| |||} } tj| D]} |j||| T|jrM|j|jdD cgc] } || g } } |D]}|j| |||<|Scc} wcc} w)z A helper function for ``trees``. :param memo: A dictionary used to record the trees that we've generated for each edge, so that when we see an edge more than once, we can reuse the same trees. N)r.r:ryrrr"symbolrr itertoolsproductrr$r&extend)rrrrrr}rr"rcp child_choiceschildrenelt unexpandedtrees rrz Chart._treesse 4<:  **,I dH %<< -DDJ6MT hhj!++D1 8CTWWRT[[XtZHWMW&--}= 8 ZX67 8 8    9=DHHJL9QR#*S"-RJR ( J' (T  !XSs EEcV|jj|ijS)z Return the set of child pointer lists for the given edge. Each child pointer list is a list of edges that have been used to form this edge. :rtype: list(list(EdgeI)) )rrrrs rrzChart.child_pointer_listss&!!%%dB/4466rNcd|d|jdzz}|j|j}}ddd|dz zz|zz}||k(r|jr|dz }n|dz }n|jr@|j d|j fk(r!|d d |z||z dz zzd |dz zzd zz }nQ|jr!|d d |z||z dz zzd |dz zzd zz }n |d d |z||z dz zzd |dz zzdzz }|d|dz zdz|j |z zz }|d |zzS)z Return a pretty-printed string representation of a given edge in this chart. :rtype: str :param width: The number of characters allotted to each index in the sentence. 2rS|. #>rrj=]-z| %s)rrrr,rr)rrwidthrrrps rpretty_format_edgezChart.pretty_format_edges} =4??,q01E dhhjS3%!),,55 C<!s s    DIIKAt7G7G3H$H 3#+#+/::SEAI=NNQTT TC     3#+#+/::SEAI=NNQTT TC 3#+#+/::SEAI=NNQTT TC uqy!C'D,<,.=s#@a AGGIq1@s+- c3BK|]}j|ywr0)r)rrrrs rrz&Chart.pretty_format..CsO//e<Os)rrrjoin)rrr_rs`` r pretty_formatzChart.pretty_format1s =4??,q01E@4@@$)*y1a**  % %e , iiOOO P +s A2c d}|dz }|dz }|dz }t|jddD]}|dk(r|dz }t|jdzD]X}|dk(sG||j|dz j ks$||j|dz j k\sO|d ||fzz }Z|d z }t|jdzD]}|d z }t|jdzD]X}|dk(sG||j|dz j ks$||j|dz j k\sO|d ||fzz }Z|d z }|dz }|dz }|dz }t|jD]}|d|j ||dzfzz } |dz }|dz }t|D]\}}t|j D]}|d||dz|dz|dzfzz }|d|j |dz|j |dz|fzz }t|j |jD]}|d||dz|dz|dzfzz }|d z }|S)Nzdigraph nltk_chart { z rankdir=LR; z node [height=0.1,width=0.1]; z* node [style=filled, color="lightgray"]; rz& node [style=filled, color="black"]; rSz %04d.%04d [label=""]; z/ x [style=invis]; x->0000.0000 [style=invis]; z {rank=same;z %04d.%04dz} z" edge [style=invis, weight=100]; z node [shape=plaintext] z 0000.0000z->%s->%04d.0000z; z edge [style=solid, weight=1]; z* %04d.%04d -> %04d.%04d [style="invis"]; z' %04d.%04d -> %04d.%04d [label="%s"]; )rnrrrrrr} enumerate)rsyxrs r dot_digraphzChart.dot_digraphJs $  // ::t~~'R0 >AAv>>4??,q01 >6QU+1133qDKKA > ??t(1,- A  A4>>+a/0 /6QU+1133qDKKA3 is not currently supported) NUM_EDGESrAssertionError)rrre1e2e3s rrz"AbstractChartRule.apply_everywheres! >>Q zz%1 1 1 ^^q  :::eWb999 :^^q  BBB#zz%"bAAAB B^^q  JJB#J#'::eWb"b#IIIJJ J !!IJ J% 2: B JsE%C.C&/C.C(7C.C*?C.C, C.(C.*C.,C.cXtjdd|jjS)Nz([a-z])([A-Z])z\1 \2)resubrr;rs rrrzAbstractChartRule.__str__s vv&$..2I2IJJrN)r;rBrCrDrrrrr6rrrrs $ K.KrrceZdZdZdZdZy)FundamentalRulea A rule that joins two adjacent edges to form a single combined edge. In particular, this rule specifies that any pair of edges - ``[A -> alpha \* B beta][i:j]`` - ``[B -> gamma \*][j:k]`` licenses the edge: - ``[A -> alpha B * beta][i:j]`` rc#@K|jrR|jrB|j|jk(r!|j |j k(sy|j |j}|j|||r|yywr0)r.r,rrr)r"rUrrrr left_edge right_edgers rrzFundamentalRule.applys  # # %&&( :#3#3#55!!#z~~'77 --jnn.>?  ( (9j IN JsBBNr;rBrCrDrrr6rrr$r$s Irr$c&eZdZdZdZdZdZdZy)SingleEdgeFundamentalRulea A rule that joins a given edge with adjacent edges in the chart, to form combined edges. In particular, this rule specifies that either of the edges: - ``[A -> alpha \* B beta][i:j]`` - ``[B -> gamma \*][j:k]`` licenses the edge: - ``[A -> alpha B * beta][i:j]`` if the other edge is already in the chart. :note: This is basically ``FundamentalRule``, with one edge left unspecified. rSc#K|jr|j|||Ed{y|j|||Ed{y7!7wr0)r._apply_incomplete_apply_complete)rrrrs rrzSingleEdgeFundamentalRule.apply*sL    --eWdC C C++E7DA A A D As!'AA AA A Ac#K|j|jd|jD]9}|j|j }|j |||s6|;ywNF)rr,r))rrr"rUrr)rrrr(r'rs rr.z)SingleEdgeFundamentalRule._apply_complete0sj  "z~~?O&  I!11*..2BCH,,Xy*M   A&A0)A0c#K|j|jd|jD]9}|j|j}|j |||s6|;ywNT)rr,r")rrr)rUrr&s rr-z+SingleEdgeFundamentalRule._apply_incomplete8si,,--/t9J9J9L'  J!11*..2BCH,,Xy*M  r1N)r;rBrCrDrrr.r-r6rrr+r+s$IB rr+ceZdZdZdZy) LeafInitRulerc#Kt|jD]4}t|j||}|j |ds1|6ywr)rnrryr}r)rrrrPrs rrzLeafInitRule.applyIsK5++-. E 5 159H||Hb) s A A AN)r;rBrCrrr6rrr5r5Fs Irr5ceZdZdZdZdZy)TopDownInitRulea A rule licensing edges corresponding to the grammar productions for the grammar's start symbol. In particular, this rule specifies that ``[S -> \* alpha][0:i]`` is licensed for each grammar production ``S -> alpha``, where ``S`` is the grammar's start symbol. rc#K|j|jD]/}tj|d}|j |ds,|1yw)Nr"rr6) productionsrrFrQr)rrrprodrs rrzTopDownInitRule.apply_sN''GMMO'< D//a8H||Hb) s A AANr)r6rrr8r8UsIrr8ceZdZdZdZdZy)TopDownPredictRulea| A rule licensing edges corresponding to the grammar productions for the nonterminal following an incomplete edge's dot. In particular, this rule specifies that ``[A -> alpha \* B beta][i:j]`` licenses the edge ``[B -> \* gamma][j:j]`` for each grammar production ``B -> gamma``. :note: This rule corresponds to the Predictor Rule in Earley parsing. rSc#K|jry|j|jD]=}tj ||j }|j |ds:|?yw)Nr:r6)r,r;r)rFrQrrrrrrr<rs rrzTopDownPredictRule.applyssc     ''DLLN'; D//dhhjAH||Hb)  A+A5.A5Nr)r6rrr>r>fsIrr>ceZdZdZdZdZy)CachedTopDownPredictRulea1 A cached version of ``TopDownPredictRule``. After the first time this rule is applied to an edge with a given ``end`` and ``next``, it will not generate any more edges for edges with that ``end`` and ``next``. If ``chart`` or ``grammar`` are changed, then the cache is flushed. c<tj|i|_yr0)r>r_doners rrz!CachedTopDownPredictRule.__init__s##D) rc#:K|jry|j|j}}t|sy|jj ||fd}|d|ur|d|ury|j |D]}|jrF|jd}t|r(||jk\s||j|k7rYtj||} |j| ds| ||f|j||f<yw)N)NNrrSr:r6)r,r)rrrErr;r$rrr}rFrQr) rrrrr)rPdoner<firstrs rrzCachedTopDownPredictRule.applys      g&  zz~~w. = 7e Q7 2 ''G'4 Dxxz 1 u% 0 0 22euzz%?P6P //e"s C>DDN)r;rBrCrDrrr6rrrCrC|s6rrCceZdZdZdZdZy)BottomUpPredictRulea" A rule licensing any edge corresponding to a production whose right-hand side begins with a complete edge's left-hand side. In particular, this rule specifies that ``[A -> alpha \*]`` licenses the edge ``[B -> \* A beta]`` for each grammar production ``B -> A beta``. rSc#K|jry|j|jD]=}tj ||j }|j |ds:|?yw)Nr$r6)r.r;r"rFrQrrr@s rrzBottomUpPredictRule.applysc     ''DHHJ'7 D//djjlCH||Hb) rANr)r6rrrJrJsIrrJceZdZdZdZdZy)BottomUpPredictCombineRulea A rule licensing any edge corresponding to a production whose right-hand side begins with a complete edge's left-hand side. In particular, this rule specifies that ``[A -> alpha \*]`` licenses the edge ``[B -> A \* beta]`` for each grammar production ``B -> A beta``. :note: This is like ``BottomUpPredictRule``, but it also applies the ``FundamentalRule`` to the resulting edge. rSc#K|jry|j|jD]R}t|j |j|j d}|j ||fsO|TywNrLrS)r.r;r"rFrr$rr@s rrz BottomUpPredictCombineRule.applyso     ''DHHJ'7 D TXXZQGH||Htg. s BB B Nr)r6rrrNrNs IrrNceZdZdZdZdZy)EmptyPredictRulezi A rule that inserts all empty productions as passive edges, in every position in the chart. rc#K|jdD]P}t|jdzD]/}tj ||}|j |ds,|1Ryw)NT)emptyrSr6)r;rnrrFrQr)rrrr<rPrs rrzEmptyPredictRule.applysj''d'3 #Du//1A56 ##33D%@<<"-"N # #s AA) A)Nr)r6rrrRrRs I#rrRceZdZdZdZy)!FilteredSingleEdgeFundamentalRulec#K|j}||jkxr|j|}|j|j d|j D]d}t |||j|js.|j|j}|j|||sa|fywr0) rrr}rrr"_bottomup_filterr$r&rUr)rrrr(r nexttokenr'rs rr.z1FilteredSingleEdgeFundamentalRule._apply_completesnn%**,,@C   "z~~?O&  #I IMMOY]]_U$55jnn6FG009jQ"N  #BC2C Cc#K|j|jd|jD]}|j}||jkxr|j |}t |||j |jsd|j|j}|j|||s|ywr3) rrr)rr}rXr$r&rUr)rrrr'r(rrYrs rr-z3FilteredSingleEdgeFundamentalRule._apply_incompletes,,--/t9J9J9L'  #J.."Ce..00DUZZ_IIMMOY]]_U$55jnn6FG009jQ"N #rZN)r;rBrCr.r-r6rrrVrVs  # #rrVceZdZdZy)"FilteredBottomUpPredictCombineRulec#K|jry|j}||jkxr|j|}|j |j D]n}t |||jst|j|j |jd}|j||fsk|pywrP) r.rrr}r;r"rXr$rFrr)rrrrrrYr<rs rrz(FilteredBottomUpPredictCombineRule.applys     hhj%**,,@C ''DHHJ'7 #DDHHJ?#DIIKTXXZK<<4'2"N  #sBC A CCN)r;rBrCrr6rrr]r]s #rr]czt||dzkry||dz}t|r||k(S|j||S)NrST)rer is_leftcorner)rrYr$r&_nexts rrXrXsH 3x37 aLE5E!!$$UI66rc@eZdZdZedddefdZdZdZd d Z e fd Z y) ChartParsera A generic chart parser. A "strategy", or list of ``ChartRuleI`` instances, is used to decide what edges to add to the chart. In particular, ``ChartParser`` uses the following algorithm to parse texts: | Until no new edges are added: | For each *rule* in *strategy*: | Apply *rule* to any applicable edges in the chart. | Return any complete parses in the chart rrTc<||_||_||_||_||_||_g|_g|_|D]_}|jdk(r|j j|.|jdk(r|jj|Yd|_ay)a Create a new chart parser, that uses ``grammar`` to parse texts. :type grammar: CFG :param grammar: The grammar used to parse texts. :type strategy: list(ChartRuleI) :param strategy: A list of rules that should be used to decide what edges to add to the chart (top-down strategy by default). :type trace: int :param trace: The level of tracing that should be used when parsing a text. ``0`` will generate no tracing output; and higher numbers will produce more verbose tracing output. :type trace_chart_width: int :param trace_chart_width: The default total width reserved for the chart in trace output. The remainder of each line will be used to display edges. :type use_agenda: bool :param use_agenda: Use an optimized agenda-based algorithm, if possible. :param chart_class: The class that should be used to create the parse charts. rrSFN) _grammar _strategy_trace_trace_chart_width _use_agenda _chart_class_axioms_inference_rulesrr)rrstrategytracetrace_chart_width use_agenda chart_classrules rrzChartParser.__init__IsB  ! "3&' " )D~~" ##D)1$%%,,T2#(  )rc|jSr0rers rrzChartParser.grammar}s }}rc||sy|dkD}|D]/}|rtd|zd}t|j||1y)NrSz%s:F)printr)rrrr new_edgesrn edge_widthprint_rule_headerrs r_trace_new_edgeszChartParser._trace_new_edgessK !AI >D edl#$)! %**4< =  >rNcJ| |j}|j}t|}|jj ||j |}|j}|j |jdzz}|rt|j||jr|jD])}t|j||}||||||+|j} |j} | j| rI| j!} | D]1} t| j||| }|r ||| |||| |z } 3| rI|Sd} | rHd} |j"D]4} t| j%||}t'|} ||| |||6| rH|S)z Return the final parse ``Chart`` from which all possible parse trees can be extracted. :param tokens: The sentence to be parsed :type tokens: list(str) :rtype: Chart rSTF)rgrzlistrecheck_coveragerjrhrrvrrirkrrlrreversepoprfrre)rrrntrace_new_edgesrrtrace_edge_widthaxiomrwinference_rulesagendarrr edges_addeds r chart_parsezChartParser.chart_parses =KKE//f $$V,!!&)-- 22u7G7G7IA7MN  %,,-=> ?    R UG!<= ui@PQ R#33O[[]F NN zz|+(D $TZZw%E FI'tYGWXi'F (& K#  NNUD $T%:%:5'%J KI"%i.K#E4ECSTU rc|j|}t|j|jj |SN)r)rrrrer)rrrrs rparsezChartParser.parses7  (ELL!4!4!6:LNOOrr0) r;rBrCrDBU_LC_STRATEGYrrrrzrr rr6rrrcrc<s9  2)h>5n(,PrrcceZdZdZdZy)TopDownChartParserzl A ``ChartParser`` using a top-down parsing strategy. See ``ChartParser`` for more information. c <tj||tfi|yr0)rcr TD_STRATEGYrr parser_argss rrzTopDownChartParser.__init__sT7KG;GrNr;rBrCrDrr6rrrrs  HrrceZdZdZdZy)BottomUpChartParserzm A ``ChartParser`` using a bottom-up parsing strategy. See ``ChartParser`` for more information. c t|trtjdtt j ||tfi|y)NzTBottomUpChartParser only works for CFG, use BottomUpProbabilisticChartParser instead)category)r:rwarningswarnDeprecationWarningrcr BU_STRATEGYrs rrzBottomUpChartParser.__init__s9 gt $ MM?+  T7KG;GrNrr6rrrrs  HrrceZdZdZdZy)BottomUpLeftCornerChartParserz A ``ChartParser`` using a bottom-up left-corner parsing strategy. This strategy is often more efficient than standard bottom-up. See ``ChartParser`` for more information. c <tj||tfi|yr0)rcrrrs rrz&BottomUpLeftCornerChartParser.__init__sT7NJkJrNrr6rrrrs  KrrceZdZdZy)LeftCornerChartParserc r|js tdtj||tfi|y)NzCLeftCornerParser only works for grammars without empty productions.) is_nonemptyrrcr LC_STRATEGYrs rrzLeftCornerChartParser.__init__s7""$X  T7KG;GrN)r;rBrCrr6rrrrsHrrcleZdZdZgdfdZdZdZdZdZdZ d Z d Z e fd Z d Zd ZdZe fdZy)SteppingChartParsera A ``ChartParser`` that allows you to step through the parsing process, adding a single edge at a time. It also allows you to change the parser's strategy or grammar midway through parsing a text. The ``initialize`` method is used to start parsing a text. ``step`` adds a single edge to the chart. ``set_strategy`` changes the strategy used by the chart parser. ``parses`` returns the set of parses that has been found by the chart parser. :ivar _restart: Records whether the parser's strategy, grammar, or chart has been changed. If so, then ``step`` must restart the parsing algorithm. rc^d|_d|_d|_tj ||||yr)_chart_current_chartrule_restartrcr)rrrmrns rrzSteppingChartParser.__init__ s, "& T7He?==  s B;C>Cc#K|j}|j}d}|dkDrAd}|jD])}||_|j ||D] }|dz }| +|dkDr@yyw)z A generator that implements the actual parsing algorithm. ``step`` iterates through this generator, and restarts it whenever the parser's strategy, grammar, or chart is modified. rSrN)rrerfrr)rrrrrrrs rrzSteppingChartParser._parse>sz  -- AoK *.'..ug>A1$KG Aos AA$"A$c|jS)z(Return the strategy used by this parser.)rfrs rrmzSteppingChartParser.strategySs ~~rc|jS)z'Return the grammar used by this parser.rtrs rrzSteppingChartParser.grammarWs }}rc|jS)z-Return the chart that is used by this parser.)rrs rrzSteppingChartParser.chart[s {{rc|jS)z||jury||_d|_y)z&Change the grammar used by the parser.NT)rer)rrs r set_grammarzSteppingChartParser.set_grammarys dmm #   rc>||jury||_d|_y)z)Load a given chart into the chart parser.NT)rr)rrs r set_chartzSteppingChartParser.set_charts DKK    rct|}|jj||j||j D]}|n|j |Sr)r|rer}rrr)rrrrs rrzSteppingChartParser.parses]f $$V,  Ay  {{j{11rN)r;rBrCrDrrrrrmrrrr rrrrrr6rrrrs[ *,1=B*'!%E (, 2rrc0ddlm}|jdS)NrCFGz S -> NP VP PP -> "with" NP NP -> NP PP VP -> VP PP VP -> Verb NP VP -> Verb NP -> Det Noun NP -> "John" NP -> "I" Det -> "the" Det -> "my" Det -> "a" Noun -> "dog" Noun -> "cookie" Verb -> "ate" Verb -> "saw" Prep -> "with" Prep -> "under" ) nltk.grammarr fromstringrs r demo_grammarrs >>  rc ddl}ddl}ddlm} m} m} t } |rtdt| tdt||j} t| t|tdtdtdtd td td td d |jjj}tt|}|dvr tdyi}dtfdtfdtfdt fd}g}||vr|g}|dk(rd}|D]}td||dztt#| ||d|}|j}|j%| }t'|j)| j+}|j|z |||d<tdt-|j/|rt-||k(sJd|r|D] }t|ntdt-|t |dvrtdt|j}t1| |}|j3| t5d D]}td!|j7tt9|j;D]\}}|d"kDs|ntd#|j7tt9|j;D]\}}|d"kDs||j|z |d$<tdt-|j=j/|r,t-t'|j)|k(sJd|r!|j)D] }t|n,tdt-t'|j)t|r|sytd%tt?d&|D}d'tA|zd(z}|jC}tE|d)*D]\}}t|||fzy)+z/ A demonstration of the chart parsers. rN)r Production nonterminalsz * Grammarz * Sentence:z 1: Top-down chart parserz 2: Bottom-up chart parserz' 3: Bottom-up left-corner chart parserz3 4: Left-corner chart parser with bottom-up filterz= 5: Stepping chart parser (alternating top-down & bottom-up)z 6: All parsersz Which parser (1-6)? r)r123456zBad parser numberzTop-downz Bottom-upzBottom-up left-cornerzFiltered left-corner)1rm3461234z * Strategy: rS)rnzNr edges in chart:zNot all parses foundz Nr trees:56z,* Strategy: Stepping (top-down vs bottom-up)z*** SWITCH TO TOP DOWNz*** SWITCH TO BOTTOM UPSteppingz* Parsing timesc32K|]}t|ywr0)re)rrs rrzdemo..0s+cS+s%zs parser: %6.3fsecc |dSr_r6)as rzdemo..3s qtr)r)#systimenltkrrrrrvsplitstdinreadlinestriprprrrrrcrr|rrrerrrrnrrrrmaxrorr)choice print_times print_grammar print_treesrnsent numparsesrrrrrrrtimes strategieschoicesrmrtrrrrqjrmaxlenformat times_itemsparsers rdemors22nG k g - $K ZZ\F &M G~ *+ +, 78 CD MN  ! &C0##%++-  [F X !" E+ &; '%~ 6$k 2 J G ( } nz(3A667  *X"6q"9 G IIKv&ell7==?34)-qj"1%& "C $67 v;)+ C-C C+  d   +s6{ + #(~ <=  IIK  6 fq A * + OOK (!"''), 1r6QY  + , OOK (!"''), 1r6QY  !IIK!Oj "C (8(8(:$;< tBIIK()Y6 N8N N6   d   +s4 #45 6  E  G +U+ +F 4< "6 6F++-KK^<$  f{"#$r__main__rv)NTFTrz$I saw John with a dog with my cookier)1rDrr!r functoolsrrrrrnltk.internalsrnltk.parse.apir nltk.treer nltk.utilr r rFryrr rr$r+r5r8r>rCrJrNrRrVr]rXrrrrrcrrrrrrrr;r6rrrs)6 $::2"!gggTD#uD#N>%u>%L\\H,$,$^+K +Kf'B))b$'"*,+61+6f+&!4. #( #*#(A#0 #)C #7N  N  N  N&(%' GP'GPTHH H+ H KKKHKH_2+_2N8  /y$x zFr