docstr: Remember that the original
  variables that we are interested in
  are actually in the bbn. However
  when we constructed the JT we did
  it out of the moralized graph.
  This means the cliques refer to
  the nodes in the moralized graph
  and not the nodes in the BBN.
  For efficiency we should come back
  to this and add some pointers
  or an index.
docstr_tok: ["Remember","that","the","original","variables","that","we","are","interested","in","are","actually","in","the","bbn",".","However","when","we","constructed","the","JT","we","did","it","out","of","the","moralized","graph",".","This","means","the","cliques","refer","to","the","nodes","in","the","moralized","graph","and","not","the","nodes","in","the","BBN",".","For","efficiency","we","should","come","back","to","this","and","add","some","pointers","or","an","index","."]
code: def marginal(self, bbn_node):
      """Remember that the original
      variables that we are interested in
      are actually in the bbn. However
      when we constructed the JT we did
      it out of the moralized graph.
      This means the cliques refer to
      the nodes in the moralized graph
      and not the nodes in the BBN.
      For efficiency we should come back
      to this and add some pointers
      or an index.
      """
  
      # First we will find the JT nodes that
      # contain the bbn_node ie all the nodes
      # that are either cliques or sepsets
      # that contain the bbn_node
      # Note that for efficiency we
      # should probably have an index
      # cached in the bbn and/or the jt.
      containing_nodes = []
  
      for node in self.clique_nodes:
          if bbn_node.name in [n.name for n in node.clique.nodes]:
              containing_nodes.append(node)
              # In theory it doesnt matter which one we
              # use so we could bale out after we
              # find the first one
              # TODO: With some better indexing we could
              # avoid searching for this node every time...
      clique_node = containing_nodes[0]
      tt = defaultdict(float)
      for k, v in list(clique_node.potential_tt.items()):
          entry = transform(
              k, clique_node.variable_names, [bbn_node.variable_name]
          )
          tt[entry] += v
  
      # Now if this node was evidenced we need to normalize
      # over the values...
      # TODO: It will be safer to copy the defaultdict to a regular dict
      return tt
  
imports: import copy
  import heapq
  import logging
  from collections import defaultdict
  from io import StringIO
  from itertools import combinations, product
  from random import choice, random
  from .exceptions import VariableNotInGraphError, VariableValueNotInDomainError
  from .graph import Node, UndirectedGraph, UndirectedNode, connect
  from .utils import get_args, get_original_factors
label_desc: Use image node_id 10 for calling the JoinTree obj's underlying member method code with example usage: obj.marginal(bbn_node) and returns: tt