docstr: Implementation of a generalized variable elimination.
  
  Parameters
  ----------
  variables: list, array-like
      variables that are not to be eliminated.
  
  operation: str ('marginalize' | 'maximize')
      The operation to do for eliminating the variable.
  
  evidence: dict
      a dict key, value pair as {var: state_of_var_observed}
      None if no evidence
  
  elimination_order: str or list (array-like)
      If str: Heuristic to use to find the elimination order.
      If array-like: The elimination order to use.
      If None: A random elimination order is used.
docstr_tok: ["Implementation","of","a","generalized","variable","elimination",".","Parameters","--","--","--","--","--","variables",":","list",",","array-like","variables","that","are","not","to","be","eliminated",".","operation",":","str","(","'marginalize","'","|","'maximize","'",")","The","operation","to","do","for","eliminating","the","variable",".","evidence",":","dict","a","dict","key",",","value","pair","as","{","var",":","state_of_var_observed","}","None","if","no","evidence","elimination_order",":","str","or","list","(","array-like",")","If","str",":","Heuristic","to","use","to","find","the","elimination","order",".","If","array-like",":","The","elimination","order","to","use",".","If","None",":","A","random","elimination","order","is","used","."]
code: def _variable_elimination(
      self,
      variables,
      operation,
      evidence=None,
      elimination_order="MinFill",
      joint=True,
      show_progress=True,
  ):
      """
      Implementation of a generalized variable elimination.
  
      Parameters
      ----------
      variables: list, array-like
          variables that are not to be eliminated.
  
      operation: str ('marginalize' | 'maximize')
          The operation to do for eliminating the variable.
  
      evidence: dict
          a dict key, value pair as {var: state_of_var_observed}
          None if no evidence
  
      elimination_order: str or list (array-like)
          If str: Heuristic to use to find the elimination order.
          If array-like: The elimination order to use.
          If None: A random elimination order is used.
      """
      # Step 1: Deal with the input arguments.
      if isinstance(variables, str):
          raise TypeError("variables must be a list of strings")
      if isinstance(evidence, str):
          raise TypeError("evidence must be a list of strings")
  
      # Dealing with the case when variables are not provided.
      if not variables:
          all_factors = []
          for factor_li in self.factors.values():
              all_factors.extend(factor_li)
          if joint:
              return factor_product(*set(all_factors))
          else:
              return set(all_factors)
  
      # Step 2: Prepare data structures to run the algorithm.
      eliminated_variables = set()
      # Get working factors and elimination order
      working_factors = self._get_working_factors(evidence)
      elimination_order = self._get_elimination_order(
          variables,
          evidence,
          elimination_order,
          show_progress=show_progress,
      )
  
      # Step 3: Run variable elimination
      if show_progress and config.SHOW_PROGRESS:
          pbar = tqdm(elimination_order)
      else:
          pbar = elimination_order
  
      for var in pbar:
          if show_progress and config.SHOW_PROGRESS:
              pbar.set_description(f"Eliminating: {var}")
          # Removing all the factors containing the variables which are
          # eliminated (as all the factors should be considered only once)
          factors = [
              factor
              for factor, _ in working_factors[var]
              if not set(factor.variables).intersection(
                  eliminated_variables
              )
          ]
          phi = factor_product(*factors)
          phi = getattr(phi, operation)([var], inplace=False)
          del working_factors[var]
          for variable in phi.variables:
              working_factors[variable].add((phi, var))
          eliminated_variables.add(var)
  
      # Step 4: Prepare variables to be returned.
      final_distribution = set()
      for node in working_factors:
          for factor, origin in working_factors[node]:
              if not set(factor.variables).intersection(
                  eliminated_variables
              ):
                  final_distribution.add((factor, origin))
      final_distribution = [factor for factor, _ in final_distribution]
  
      if joint:
          if isinstance(self.model, BayesianNetwork):
              return factor_product(*final_distribution).normalize(
                  inplace=False
              )
          else:
              return factor_product(*final_distribution)
      else:
          query_var_factor = {}
          if isinstance(self.model, BayesianNetwork):
              for query_var in variables:
                  phi = factor_product(*final_distribution)
                  query_var_factor[query_var] = phi.marginalize(
                      list(set(variables) - set([query_var])),
                      inplace=False,
                  ).normalize(inplace=False)
          else:
              for query_var in variables:
                  phi = factor_product(*final_distribution)
                  query_var_factor[query_var] = phi.marginalize(
                      list(set(variables) - set([query_var])),
                      inplace=False,
                  )
          return query_var_factor
  
imports: import copy
  import itertools
  import networkx
  import numpy
  from opt_einsum import contract
  from tqdm.auto import tqdm
  from pgmpy import config
  from pgmpy.factors import factor_product
  from pgmpy.factors.discrete import DiscreteFactor
  from pgmpy.inference import Inference
  from pgmpy.inference.EliminationOrder import MinFill, MinNeighbors, MinWeight, WeightedMinFill
  from pgmpy.models import BayesianNetwork, DynamicBayesianNetwork, JunctionTree, MarkovNetwork
  from pgmpy.utils import compat_fns
label_desc: Use image node_id 3 for calling the VariableElimination obj's underlying member method code with example usage: obj._variable_elimination(variables, operation, evidence, elimination_order, joint, show_progress) and returns: query_var_factor, factor_product, set, factor_product, factor_product