code: def _categorical_exact(
      X,
      sample_weight=None,
      include_parents=None,
      exclude_parents=None,
      pseudocount=0,
      penalty=None,
      max_parents=None,
  ):
      """Find the optimal graph over a set of variables with no other knowledge.
  
      This is the naive dynamic programming structure learning task where the
      optimal graph is identified from a set of variables using an order graph
      and parent graphs. This can be used either when no constraint graph is
      provided or for a SCC which is made up of a node containing a self-loop.
      This is a reference implementation that uses the naive shortest path
      algorithm over the entire order graph. The 'exact' option uses the A* path
      in order to avoid considering the full order graph.
  
  
      Parameters
      ----------
      X: numpy.ndarray, shape=(n, d)
              The data to fit the structure too, where each row is a sample and
              each column corresponds to the associated variable.
  
      sample_weight: numpy.ndarray, shape=(n,)
              The weight of each sample as a positive double. Default is None.
  
      include_parents: list or None
              A set of (parent, child) tuples where each tuple is an edge that
              must exist in the found structure.
  
      exclude_parents: list or None
              A set of (parent, child) tuples where each tuple is an edge that
              cannot exist in the found structure.
  
      penalty: float or None, optional
              The weighting of the model complexity term in the objective function.
              Increasing this value will encourage sparsity whereas setting the value
              to 0 will result in an unregularized structure. Default is
              log2(|D|) / 2 where |D| is the sum of the weights of the data.
  
      max_parents: int
              The maximum number of parents a node can have. If used, this means
              using the k-learn procedure. Can drastically speed up algorithms.
              If -1, no max on parents. Default is -1.
  
  
      Returns
      -------
      structure: tuple, shape=(d,)
              The parents for each variable in this SCC
      """
  
      X = _check_parameter(
          _cast_as_tensor(X),
          "X",
          min_value=0,
          ndim=2,
          dtypes=(torch.int32, torch.int64),
      )
      sample_weight = _check_parameter(
          _cast_as_tensor(sample_weight), "X", min_value=0, ndim=1
      )
  
      n, d = X.shape
      n_categories = X.max(axis=0).values + 1
  
      if sample_weight is None:
          sample_weight = torch.ones(n)
  
      w = sample_weight.sum()
      if max_parents is None:
          max_parents = int(torch.log2(2 * w / torch.log2(w)).item())
  
      parent_graphs = []
      for i in range(d):
          exclude = (
              None if exclude_parents is None else exclude_parents[i]
          )
          parent_set = tuple(set(range(d)) - set([i]))
  
          parent_graph = _generate_parent_graph(
              X,
              sample_weight=sample_weight,
              n_categories=n_categories,
              column_idx=i,
              include_parents=include_parents,
              exclude_parents=exclude,
              pseudocount=pseudocount,
              penalty=penalty,
              max_parents=max_parents,
              parent_set=parent_set,
          )
          parent_graphs.append(parent_graph)
  
      order_graph = nx.DiGraph()
  
      for i in range(d + 1):
          for subset in itertools.combinations(range(d), i):
              order_graph.add_node(subset)
  
              for variable in subset:
                  parent = tuple(v for v in subset if v != variable)
  
                  structure, weight = parent_graphs[variable][parent]
                  weight = -weight if weight < 0 else 0
                  order_graph.add_edge(
                      parent, subset, weight=weight, structure=structure
                  )
  
      path = sorted(
          nx.all_shortest_paths(
              order_graph,
              source=(),
              target=tuple(range(d)),
              weight="weight",
          )
      )[0]
  
      score, structure = 0, list(None for i in range(d))
      for u, v in zip(path[:-1], path[1:]):
          idx = list(set(v) - set(u))[0]
          parents = order_graph.get_edge_data(u, v)["structure"]
          structure[idx] = parents
          score -= order_graph.get_edge_data(u, v)["weight"]
  
      return tuple(structure)
  
imports: import time
  import numpy
  import torch
  import itertools
  import networkx
  from ._utils import _cast_as_tensor
  from ._utils import _cast_as_parameter
  from ._utils import _update_parameter
  from ._utils import _check_parameter
  from ._utils import _reshape_weights
  from .distributions._distribution import Distribution
  from .distributions import Categorical
  from .distributions import JointCategorical
  from .distributions import ConditionalCategorical
  from .factor_graph import FactorGraph
label_desc: Use image node_id 4 for calling a global function with example usage: _categorical_exact(X, sample_weight, include_parents, exclude_parents, pseudocount, penalty, max_parents) and returns: tuple