code: def apply(self, chart, grammar, left_edge, right_edge):
      # Make sure the rule is applicable.
      if not (
          left_edge.end() == right_edge.start()
          and left_edge.nextsym() == right_edge.lhs()
          and left_edge.is_incomplete()
          and right_edge.is_complete()
      ):
          return
  
      # Construct the new edge.
      p = left_edge.prob() * right_edge.prob()
      new_edge = ProbabilisticTreeEdge(
          p,
          span=(left_edge.start(), right_edge.end()),
          lhs=left_edge.lhs(),
          rhs=left_edge.rhs(),
          dot=left_edge.dot() + 1,
      )
  
      # Add it to the chart, with appropriate child pointers.
      changed_chart = False
      for cpl1 in chart.child_pointer_lists(left_edge):
          if chart.insert(new_edge, cpl1 + (right_edge,)):
              changed_chart = True
  
      # If we changed the chart, then generate the edge.
      if changed_chart:
          yield new_edge
  
imports: import random
  from functools import reduce
  from nltk.grammar import PCFG, Nonterminal
  from nltk.parse.api import ParserI
  from nltk.parse.chart import AbstractChartRule, Chart, LeafEdge, TreeEdge
  from nltk.tree import ProbabilisticTree, Tree
label_desc: Use image node_id 1 for calling the ProbabilisticFundamentalRule obj's underlying member method code with example usage: obj.apply(chart, grammar, left_edge, right_edge) without return types