code: def apply(self, chart, grammar, edge):
      if edge.is_incomplete():
          return
      found = edge.lhs()
      for prod in grammar.productions(rhs=found):
          bindings = {}
          if isinstance(edge, FeatureTreeEdge):
              _next = prod.rhs()[0]
              if not is_nonterminal(_next):
                  continue
  
              # We rename vars here, because we don't want variables
              # from the two different productions to match.
              used_vars = find_variables(
                  (prod.lhs(),) + prod.rhs(), fs_class=FeatStruct
              )
              found = found.rename_variables(used_vars=used_vars)
  
              result = unify(_next, found, bindings, rename_vars=False)
              if result is None:
                  continue
  
          new_edge = FeatureTreeEdge.from_production(
              prod, edge.start()
          ).move_dot_forward(edge.end(), bindings)
          if chart.insert(new_edge, (edge,)):
              yield new_edge
  
imports: from time import perf_counter
  from nltk.featstruct import TYPE, FeatStruct, find_variables, unify
  from nltk.grammar import CFG, FeatStructNonterminal, Nonterminal, Production, is_nonterminal, is_terminal
  from nltk.parse.chart import BottomUpPredictCombineRule, BottomUpPredictRule, CachedTopDownPredictRule, Chart, ChartParser, EdgeI, EmptyPredictRule, FundamentalRule, LeafInitRule, SingleEdgeFundamentalRule, TopDownInitRule, TreeEdge
  from nltk.sem import logic
  from nltk.tree import Tree
label_desc: Use image node_id 1 for calling the FeatureBottomUpPredictCombineRule obj's underlying member method code with example usage: obj.apply(chart, grammar, edge) without return types