code: def _categorical_chow_liu(
      X, sample_weight=None, pseudocount=0.0, root=0
  ):
      """An internal function for calculating a Chow-Liu tree.
  
      This function calculates a Chow-Liu tree on categorical data which is
      potentially weighted. A Chow-Liu tree is essentially a maximum spanning
      tree on the information content that adding each new variable might
      add.
  
  
      Parameters
      ----------
      X: torch.tensor, 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: torch.tensor or None, shape=(n,)
              The weight of each sample as a positive double. If None, all items are
              weighted equally.
  
      pseudocount: double
              A pseudocount to add to each count. Default is 0.
  
      root: int
              When using a tree-based algorithm, like Chow-Liu, sets the variable
              that is the root of the tree.
  
  
      Returns
      -------
      structure: tuple
              A tuple of tuples where the internal tuples indicate the parents of
              that variable.
      """
  
      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
      )
  
      pseudocount = _check_parameter(
          pseudocount, "pseudocount", min_value=0, ndim=0
      )
      root = _check_parameter(
          root,
          "root",
          min_value=0,
          max_value=X.shape[1],
          dtypes=(
              int,
              numpy.int32,
              numpy.int64,
              torch.int32,
              torch.int64,
          ),
      )
  
      n, d = X.shape
  
      if sample_weight is None:
          sample_weight = torch.ones(n)
  
      start = time.time()
      n_categories = tuple(x.item() for x in X.max(dim=0).values + 1)
      max_categories = max(n_categories)
  
      c = max_categories**2
      dtype = sample_weight.dtype
      count = torch.empty(c, d, dtype=dtype, device=X.device)
      mutual_info = torch.zeros(d, d, dtype=dtype, device=X.device)
  
      marginals_i = torch.empty(d, c, dtype=dtype, device=X.device)
      marginals_r = torch.empty(d, c, dtype=dtype, device=X.device)
  
      for j in range(d):
          marg = torch.zeros(
              max_categories, dtype=dtype, device=X.device
          )
          marg.scatter_add_(0, X[:, j], sample_weight)
  
          marginals_i[j] = marg.repeat_interleave(max_categories)
          marginals_r[j] = marg.repeat(max_categories)
  
      w = sample_weight.unsqueeze(-1).expand(-1, d)
  
      for j in range(d):
          X_j = X[:, j : j + 1] * max_categories + X
          m = marginals_i[j : j + 1] * marginals_r
  
          count[:] = pseudocount
          count.scatter_add_(0, X_j, w)
  
          mutual_info[j] -= torch.sum(
              count * torch.log(count / m.T), dim=0
          )
          mutual_info[:, j] = mutual_info[j]
  
      structure = [[] for i in range(d)]
      visited = [root]
      unvisited = list(range(d))
      unvisited.remove(root)
  
      for i in range(d - 1):
          min_score = float("inf")
          min_x = -1
          min_y = -1
  
          idx = mutual_info[visited][:, unvisited].argmin()
          row, col = (idx // len(unvisited)).item(), (
              idx % len(unvisited)
          ).item()
          min_x, min_y = visited[row], unvisited[col]
  
          structure[min_y].append(min_x)
          visited.append(min_y)
          unvisited.remove(min_y)
  
      return tuple(tuple(x) for x in 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 3 for calling a global function with example usage: _categorical_chow_liu(X, sample_weight, pseudocount, root) and returns: tuple