code: def identify_ate_effect(
      graph: nx.DiGraph,
      action_nodes: List[str],
      outcome_nodes: List[str],
      observed_nodes: List[str],
      backdoor_adjustment: BackdoorAdjustment,
      optimize_backdoor: bool,
      estimand_type: EstimandType,
      costs: List,
      conditional_node_names: List[str] = None,
  ):
      estimands_dict = {}
      mediation_first_stage_confounders = None
      mediation_second_stage_confounders = None
      ### 1. BACKDOOR IDENTIFICATION
      # Pick algorithm to compute backdoor sets according to method chosen
      if backdoor_adjustment not in EFFICIENT_METHODS:
          # First, checking if there are any valid backdoor adjustment sets
          if optimize_backdoor == False:
              backdoor_sets = identify_backdoor(
                  graph,
                  action_nodes,
                  outcome_nodes,
                  observed_nodes,
                  backdoor_adjustment,
              )
          else:
              from dowhy.causal_identifier.backdoor import Backdoor
  
              path = Backdoor(graph, action_nodes, outcome_nodes)
              backdoor_sets = path.get_backdoor_vars()
      elif backdoor_adjustment in EFFICIENT_METHODS:
          backdoor_sets = identify_efficient_backdoor(
              graph,
              action_nodes,
              outcome_nodes,
              observed_nodes,
              backdoor_adjustment,
              costs,
              conditional_node_names=conditional_node_names,
          )
      (
          estimands_dict,
          backdoor_variables_dict,
      ) = build_backdoor_estimands_dict(
          action_nodes,
          outcome_nodes,
          observed_nodes,
          backdoor_sets,
          estimands_dict,
      )
      # Setting default "backdoor" identification adjustment set
      default_backdoor_id = get_default_backdoor_set_id(
          graph, action_nodes, outcome_nodes, backdoor_variables_dict
      )
      if len(backdoor_variables_dict) > 0:
          estimands_dict["backdoor"] = estimands_dict.get(
              str(default_backdoor_id), None
          )
          backdoor_variables_dict[
              "backdoor"
          ] = backdoor_variables_dict.get(
              str(default_backdoor_id), None
          )
      else:
          estimands_dict["backdoor"] = None
      ### 2. INSTRUMENTAL VARIABLE IDENTIFICATION
      # Now checking if there is also a valid iv estimand
      instrument_names = get_instruments(
          graph, action_nodes, outcome_nodes
      )
      logger.info(
          "Instrumental variables for treatment and outcome:"
          + str(instrument_names)
      )
      if len(instrument_names) > 0:
          iv_estimand_expr = construct_iv_estimand(
              action_nodes,
              outcome_nodes,
              instrument_names,
          )
          logger.debug(
              "Identified expression = " + str(iv_estimand_expr)
          )
          estimands_dict["iv"] = iv_estimand_expr
      else:
          estimands_dict["iv"] = None
  
      ### 3. FRONTDOOR IDENTIFICATION
      # Now checking if there is a valid frontdoor variable
      frontdoor_variables_names = identify_frontdoor(
          graph, action_nodes, outcome_nodes, observed_nodes
      )
      logger.info(
          "Frontdoor variables for treatment and outcome:"
          + str(frontdoor_variables_names)
      )
      if len(frontdoor_variables_names) > 0:
          frontdoor_estimand_expr = construct_frontdoor_estimand(
              action_nodes,
              outcome_nodes,
              frontdoor_variables_names,
          )
          logger.debug(
              "Identified expression = " + str(frontdoor_estimand_expr)
          )
          estimands_dict["frontdoor"] = frontdoor_estimand_expr
          mediation_first_stage_confounders = (
              identify_mediation_first_stage_confounders(
                  graph,
                  action_nodes,
                  outcome_nodes,
                  frontdoor_variables_names,
                  observed_nodes,
                  backdoor_adjustment,
              )
          )
          mediation_second_stage_confounders = (
              identify_mediation_second_stage_confounders(
                  graph,
                  action_nodes,
                  frontdoor_variables_names,
                  outcome_nodes,
                  observed_nodes,
                  backdoor_adjustment,
              )
          )
      else:
          estimands_dict["frontdoor"] = None
  
      # Finally returning the estimand object
      estimand = IdentifiedEstimand(
          None,
          treatment_variable=action_nodes,
          outcome_variable=outcome_nodes,
          estimand_type=estimand_type,
          estimands=estimands_dict,
          backdoor_variables=backdoor_variables_dict,
          instrumental_variables=instrument_names,
          frontdoor_variables=frontdoor_variables_names,
          mediation_first_stage_confounders=mediation_first_stage_confounders,
          mediation_second_stage_confounders=mediation_second_stage_confounders,
          default_backdoor_id=default_backdoor_id,
      )
      return estimand
  
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 2 for calling a global function with example usage: identify_ate_effect(graph, action_nodes, outcome_nodes, observed_nodes, backdoor_adjustment, optimize_backdoor, estimand_type, costs, conditional_node_names) and returns: estimand