code: def identify_effect_auto(
      graph: nx.DiGraph,
      action_nodes: Union[str, List[str]],
      outcome_nodes: Union[str, List[str]],
      observed_nodes: Union[str, List[str]],
      estimand_type: EstimandType,
      conditional_node_names: List[str] = None,
      backdoor_adjustment: BackdoorAdjustment = BackdoorAdjustment.BACKDOOR_DEFAULT,
      optimize_backdoor: bool = False,
      costs: Optional[List] = None,
  ) -> IdentifiedEstimand:
      """Main method that returns an identified estimand (if one exists).
  
      If estimand_type is non-parametric ATE, then  uses backdoor, instrumental variable and frontdoor identification methods,  to check if an identified estimand exists, based on the causal graph.
  
      :param optimize_backdoor: if True, uses an optimised algorithm to compute the backdoor sets
      :param costs: non-negative costs associated with variables in the graph. Only used
      for estimand_type='non-parametric-ate' and backdoor_adjustment='efficient-mincost-adjustment'. If
      no costs are provided by the user, and backdoor_adjustment='efficient-mincost-adjustment', costs
      are assumed to be equal to one for all variables in the graph.
      :param conditional_node_names: variables that are used to determine treatment. If none are
      provided, it is assumed that the intervention is static.
      :returns:  target estimand, an instance of the IdentifiedEstimand class
      """
  
      observed_nodes = parse_state(observed_nodes)
      action_nodes = parse_state(action_nodes)
      outcome_nodes = parse_state(outcome_nodes)
  
      # First, check if there is a directed path from action to outcome
      if not has_directed_path(graph, action_nodes, outcome_nodes):
          logger.warn(
              "No directed path from treatment to outcome. Causal Effect is zero."
          )
          return IdentifiedEstimand(
              None,
              treatment_variable=action_nodes,
              outcome_variable=outcome_nodes,
              no_directed_path=True,
          )
      if estimand_type == EstimandType.NONPARAMETRIC_ATE:
          return identify_ate_effect(
              graph,
              action_nodes,
              outcome_nodes,
              observed_nodes,
              backdoor_adjustment,
              optimize_backdoor,
              estimand_type,
              costs,
              conditional_node_names,
          )
      elif estimand_type == EstimandType.NONPARAMETRIC_NDE:
          return identify_nde_effect(
              graph,
              action_nodes,
              outcome_nodes,
              observed_nodes,
              backdoor_adjustment,
              estimand_type,
          )
      elif estimand_type == EstimandType.NONPARAMETRIC_NIE:
          return identify_nie_effect(
              graph,
              action_nodes,
              outcome_nodes,
              observed_nodes,
              backdoor_adjustment,
              estimand_type,
          )
      elif estimand_type == EstimandType.NONPARAMETRIC_CDE:
          return identify_cde_effect(
              graph,
              action_nodes,
              outcome_nodes,
              observed_nodes,
              backdoor_adjustment,
              estimand_type,
          )
      else:
          raise ValueError(
              "Estimand type is not supported. Use either {0}, {1}, or {2}.".format(
                  EstimandType.NONPARAMETRIC_ATE,
                  EstimandType.NONPARAMETRIC_CDE,
                  EstimandType.NONPARAMETRIC_NDE,
                  EstimandType.NONPARAMETRIC_NIE,
              )
          )
  
imports: import itertools
  import logging
  from enum import Enum
  from typing import Dict, List, Optional, Union
  import networkx
  import sympy
  import sympy.stats
  from dowhy.causal_identifier.efficient_backdoor import EfficientBackdoor
  from dowhy.causal_identifier.identified_estimand import IdentifiedEstimand
  from dowhy.graph import check_dseparation, check_valid_backdoor_set, check_valid_frontdoor_set, check_valid_mediation_set, do_surgery, get_all_directed_paths, get_backdoor_paths, get_descendants, get_instruments, has_directed_path
  from dowhy.utils.api import parse_state
label_desc: Use image node_id 1 for calling a global function with example usage: identify_effect_auto(graph, action_nodes, outcome_nodes, observed_nodes, estimand_type, conditional_node_names, backdoor_adjustment, optimize_backdoor, costs) and returns: IdentifiedEstimand, identify_ate_effect, identify_nde_effect, identify_nie_effect, identify_cde_effect