class_docstr: Base class for all Directed Graphical Models.
  
  Each node in the graph can represent either a random variable, `Factor`,
  or a cluster of random variables. Edges in the graph represent the
  dependencies between these.
  
  Parameters
  ----------
  data: input graph
      Data to initialize graph. If data=None (default) an empty graph is
      created. The data can be an edge list or any Networkx graph object.
  
  Examples
  --------
  Create an empty DAG with no nodes and no edges
  
  >>> from pgmpy.base import DAG
  >>> G = DAG()
  
  G can be grown in several ways:
  
  **Nodes:**
  
  Add one node at a time:
  
  >>> G.add_node(node='a')
  
  Add the nodes from any container (a list, set or tuple or the nodes
  from another graph).
  
  >>> G.add_nodes_from(nodes=['a', 'b'])
  
  **Edges:**
  
  G can also be grown by adding edges.
  
  Add one edge,
  
  >>> G.add_edge(u='a', v='b')
  
  a list of edges,
  
  >>> G.add_edges_from(ebunch=[('a', 'b'), ('b', 'c')])
  
  If some edges connect nodes not yet in the model, the nodes
  are added automatically. There are no errors when adding
  nodes or edges that already exist.
  
  **Shortcuts:**
  
  Many common graph features allow python syntax for speed reporting.
  
  >>> 'a' in G     # check if node in graph
  True
  >>> len(G)  # number of nodes in graph
  3
class_docstr_tok: ["Base","class","for","all","Directed","Graphical","Models",".","Each","node","in","the","graph","can","represent","either","a","random","variable",",","`","Factor","`",",","or","a","cluster","of","random","variables",".","Edges","in","the","graph","represent","the","dependencies","between","these",".","Parameters","--","--","--","--","--","data",":","input","graph","Data","to","initialize","graph",".","If","data=None","(","default",")","an","empty","graph","is","created",".","The","data","can","be","an","edge","list","or","any","Networkx","graph","object",".","Examples","--","--","--","--","Create","an","empty","DAG","with","no","nodes","and","no","edges",">",">",">","from","pgmpy.base","import","DAG",">",">",">","G","=","DAG","(",")","G","can","be","grown","in","several","ways",":","*","*","Nodes",":","*","*","Add","one","node","at","a","time",":",">",">",">","G.add_node","(","node=","'","a","'",")","Add","the","nodes","from","any","container","(","a","list",",","set","or","tuple","or","the","nodes","from","another","graph",")",".",">",">",">","G.add_nodes_from","(","nodes=","[","'","a","'",",","'","b","'","]",")","*","*","Edges",":","*","*","G","can","also","be","grown","by","adding","edges",".","Add","one","edge",",",">",">",">","G.add_edge","(","u=","'","a","'",",","v=","'","b","'",")","a","list","of","edges",",",">",">",">","G.add_edges_from","(","ebunch=","[","(","'","a","'",",","'","b","'",")",",","(","'","b","'",",","'","c","'",")","]",")","If","some","edges","connect","nodes","not","yet","in","the","model",",","the","nodes","are","added","automatically",".","There","are","no","errors","when","adding","nodes","or","edges","that","already","exist",".","*","*","Shortcuts",":","*","*","Many","common","graph","features","allow","python","syntax","for","speed","reporting",".",">",">",">","'","a","'","in","G","#","check","if","node","in","graph","True",">",">",">","len","(","G",")","#","number","of","nodes","in","graph","3"]
docstr: Returns a dictionary with the given variables as keys and all the nodes reachable
  from that respective variable as values.
  
  Parameters
  ----------
  variables: str or array like
      variables whose active trails are to be found.
  
  observed : List of nodes (optional)
      If given the active trails would be computed assuming these nodes to be
      observed.
  
  include_latents: boolean (default: False)
      Whether to include the latent variables in the returned active trail nodes.
  
  Examples
  --------
  >>> from pgmpy.base import DAG
  >>> student = DAG()
  >>> student.add_nodes_from(['diff', 'intel', 'grades'])
  >>> student.add_edges_from([('diff', 'grades'), ('intel', 'grades')])
  >>> student.active_trail_nodes('diff')
  {'diff': {'diff', 'grades'}}
  >>> student.active_trail_nodes(['diff', 'intel'], observed='grades')
  {'diff': {'diff', 'intel'}, 'intel': {'diff', 'intel'}}
  
  References
  ----------
  Details of the algorithm can be found in 'Probabilistic Graphical Model
  Principles and Techniques' - Koller and Friedman
  Page 75 Algorithm 3.1
docstr_tok: ["Returns","a","dictionary","with","the","given","variables","as","keys","and","all","the","nodes","reachable","from","that","respective","variable","as","values",".","Parameters","--","--","--","--","--","variables",":","str","or","array","like","variables","whose","active","trails","are","to","be","found",".","observed",":","List","of","nodes","(","optional",")","If","given","the","active","trails","would","be","computed","assuming","these","nodes","to","be","observed",".","include_latents",":","boolean","(","default",":","False",")","Whether","to","include","the","latent","variables","in","the","returned","active","trail","nodes",".","Examples","--","--","--","--",">",">",">","from","pgmpy.base","import","DAG",">",">",">","student","=","DAG","(",")",">",">",">","student.add_nodes_from","(","[","'diff","'",",","'intel","'",",","'grades","'","]",")",">",">",">","student.add_edges_from","(","[","(","'diff","'",",","'grades","'",")",",","(","'intel","'",",","'grades","'",")","]",")",">",">",">","student.active_trail_nodes","(","'diff","'",")","{","'diff","'",":","{","'diff","'",",","'grades","'","}","}",">",">",">","student.active_trail_nodes","(","[","'diff","'",",","'intel","'","]",",","observed='grades","'",")","{","'diff","'",":","{","'diff","'",",","'intel","'","}",",","'intel","'",":","{","'diff","'",",","'intel","'","}","}","References","--","--","--","--","--","Details","of","the","algorithm","can","be","found","in","'Probabilistic","Graphical","Model","Principles","and","Techniques","'","-","Koller","and","Friedman","Page","75","Algorithm","3.1"]
code: def active_trail_nodes(
      self, variables, observed=None, include_latents=False
  ):
      """
      Returns a dictionary with the given variables as keys and all the nodes reachable
      from that respective variable as values.
  
      Parameters
      ----------
      variables: str or array like
          variables whose active trails are to be found.
  
      observed : List of nodes (optional)
          If given the active trails would be computed assuming these nodes to be
          observed.
  
      include_latents: boolean (default: False)
          Whether to include the latent variables in the returned active trail nodes.
  
      Examples
      --------
      >>> from pgmpy.base import DAG
      >>> student = DAG()
      >>> student.add_nodes_from(['diff', 'intel', 'grades'])
      >>> student.add_edges_from([('diff', 'grades'), ('intel', 'grades')])
      >>> student.active_trail_nodes('diff')
      {'diff': {'diff', 'grades'}}
      >>> student.active_trail_nodes(['diff', 'intel'], observed='grades')
      {'diff': {'diff', 'intel'}, 'intel': {'diff', 'intel'}}
  
      References
      ----------
      Details of the algorithm can be found in 'Probabilistic Graphical Model
      Principles and Techniques' - Koller and Friedman
      Page 75 Algorithm 3.1
      """
      if observed:
          if isinstance(observed, set):
              observed = list(observed)
  
          observed_list = (
              observed
              if isinstance(observed, (list, tuple))
              else [observed]
          )
      else:
          observed_list = []
      ancestors_list = self._get_ancestors_of(observed_list)
  
      # Direction of flow of information
      # up ->  from parent to child
      # down -> from child to parent
  
      active_trails = {}
      for start in (
          variables if isinstance(variables, list) else [variables]
      ):
          visit_list = set()
          visit_list.add((start, "up"))
          traversed_list = set()
          active_nodes = set()
          while visit_list:
              node, direction = visit_list.pop()
              if (node, direction) not in traversed_list:
                  if node not in observed_list:
                      active_nodes.add(node)
                  traversed_list.add((node, direction))
                  if direction == "up" and node not in observed_list:
                      for parent in self.predecessors(node):
                          visit_list.add((parent, "up"))
                      for child in self.successors(node):
                          visit_list.add((child, "down"))
                  elif direction == "down":
                      if node not in observed_list:
                          for child in self.successors(node):
                              visit_list.add((child, "down"))
                      if node in ancestors_list:
                          for parent in self.predecessors(node):
                              visit_list.add((parent, "up"))
          if include_latents:
              active_trails[start] = active_nodes
          else:
              active_trails[start] = active_nodes - self.latents
  
      return active_trails
  
imports: import itertools
  import networkx
  import numpy
  from pgmpy.base import UndirectedGraph
  from pgmpy.global_vars import logger
  from pgmpy.independencies import Independencies
label_desc: Use image node_id 20 for calling the DAG obj's underlying member method code with example usage: obj.active_trail_nodes(variables, observed, include_latents) and returns: active_trails