class_docstr: A Directed Acyclic Graph
class_docstr_tok: ["A","Directed","Acyclic","Graph"]
code: def query(self, **kwds):
      # First check that the keyvals
      # provided are valid for this graph...
      self.validate_keyvals(**kwds)
      jt = self.build_join_tree()
      assignments = jt.assign_clusters(self)
      jt.initialize_potentials(assignments, self, kwds)
  
      jt.propagate()
      marginals = {}
      normalizers = defaultdict(float)
  
      for node in self.nodes:
          for k, v in list(jt.marginal(node).items()):
              # For a single node the
              # key for the marginal tt always
              # has just one argument so we
              # will unpack it here
              marginals[k[0]] = v
              # If we had any evidence then we
              # need to normalize all the variables
              # not evidenced.
              if kwds:
                  normalizers[k[0][0]] += v
  
      if kwds:
          for k, v in marginals.items():
              if normalizers[k[0]] != 0:
                  marginals[k] /= normalizers[k[0]]
  
      return marginals
  
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 5 for calling the BBN obj's underlying member method code with example usage: obj.query() and returns: marginals