code: def mechanism_change_test(
      target_original_data: np.ndarray,
      target_new_data: np.ndarray,
      parents_original_data: Optional[np.ndarray] = None,
      parents_new_data: Optional[np.ndarray] = None,
      independence_test: Callable[
          [np.ndarray, np.ndarray], float
      ] = kernel_based,
      conditional_independence_test: Callable[
          [np.ndarray, np.ndarray, np.ndarray], float
      ] = kernel_based,
  ) -> float:
      """Estimates a p-value for the null hypothesis that the original and new data were generated by the same mechanism.
      Here, we check the dependency between binary labels indicating whether a sample is from the original or a new
      data set. If the labels do not provide information to determine if a sample is coming from the original/new
      distribution, then it is likely that the mechanism has not changed.
  
      For non-root nodes, samples from parent variables are needed as conditioning variables. This is, testing the
      null hypothesis that the data were generated by the same mechanism given the parent samples. By this, we incorporate
      upstream changes that might have impacted the parents, but not the target node itself.
  
      :param target_original_data: Samples of the node from the original data set.
      :param target_new_data: Samples of the node from the new data set.
      :param parents_original_data: Samples from parents of the node from the original data set.
      :param parents_new_data: Samples from parents of the node from the new data set.
      :param independence_test: Unconditional independence test. This is used to identify mechanism changes in nodes
                                without parents.
      :param conditional_independence_test: Conditional independence test. This is used to identify mechanism changes in
                                            nodes with parents.
      :return: A p-value for the null hypothesis that the mechanism has not changed.
      """
      causal_graph: DirectedGraph
  
      if parents_original_data is not None and parents_new_data is None:
          raise ValueError(
              "Original parents data were given, but no new parents data!"
          )
      if parents_original_data is None and parents_new_data is not None:
          raise ValueError(
              "New parents data were given, but no original parents data!"
          )
  
      num_samples_for_testing = min(
          target_original_data.shape[0], target_new_data.shape[0]
      )
      data_set_indices = np.ones(num_samples_for_testing * 2)
      data_set_indices[num_samples_for_testing:] = -1
      data_set_indices = data_set_indices.astype(str)
  
      original_indices = np.random.choice(
          target_original_data.shape[0],
          num_samples_for_testing,
          replace=False,
      )
      new_indices = np.random.choice(
          target_new_data.shape[0],
          num_samples_for_testing,
          replace=False,
      )
  
      joint_target_samples = np.vstack(
          [
              shape_into_2d(target_original_data[original_indices]),
              shape_into_2d(target_new_data[new_indices]),
          ]
      )
  
      if parents_original_data is None:
          return independence_test(
              joint_target_samples, data_set_indices
          )
      else:
          parents_new_data: np.ndarray
          joint_parent_data = np.vstack(
              [
                  shape_into_2d(
                      parents_original_data[original_indices]
                  ),
                  shape_into_2d(parents_new_data[new_indices]),
              ]
          )
  
          return conditional_independence_test(
              joint_target_samples, data_set_indices, joint_parent_data
          )
  
imports: import logging
  from typing import Any, Callable, Dict, List, Optional, Tuple, Union
  import networkx
  import numpy
  import pandas
  from numpy.matlib import repmat
  from statsmodels.stats.multitest import multipletests
  from tqdm import tqdm
  from dowhy.gcm.auto import AssignmentQuality, assign_causal_mechanism_node, assign_causal_mechanisms
  from dowhy.gcm.causal_mechanisms import ConditionalStochasticModel
  from dowhy.gcm.causal_models import PARENTS_DURING_FIT, ProbabilisticCausalModel, clone_causal_models, validate_causal_dag
  from dowhy.gcm.divergence import auto_estimate_kl_divergence
  from dowhy.gcm.fitting_sampling import draw_samples, fit_causal_model_of_target
  from dowhy.gcm.independence_test.kernel import kernel_based
  from dowhy.gcm.shapley import ShapleyConfig, estimate_shapley_values
  from dowhy.gcm.util.general import shape_into_2d
  from dowhy.graph import DirectedGraph, get_ordered_predecessors, is_root_node, node_connected_subgraph_view
label_desc: Use image node_id 1 for calling a global function with example usage: mechanism_change_test(target_original_data, target_new_data, parents_original_data, parents_new_data, independence_test, conditional_independence_test) and returns: independence_test, conditional_independence_test