code: def falsify_graph(
      causal_graph: DirectedGraph,
      data: pd.DataFrame,
      suggestions: bool = False,
      independence_test: Callable[
          [np.ndarray, np.ndarray], float
      ] = kernel_based,
      conditional_independence_test: Callable[
          [np.ndarray, np.ndarray, np.ndarray], float
      ] = kernel_based,
      significance_level: float = 0.05,
      significance_ci: float = 0.05,
      n_permutations: Optional[int] = None,
      show_progress_bar: Optional[bool] = None,
      n_jobs: Optional[int] = None,
      plot_histogram: bool = False,
      plot_kwargs: Optional[Dict] = None,
      allow_data_subset: bool = True,
  ) -> EvaluationResult:
      """
      Falsify a given DAG using observational data.
  
      This method returns the result of a permutation-test to falsify a user-given DAG using observational data. To this
      end we construct the test statistics by testing the violations of local Markov conditions (LMC) implied by
      the graph using conditional independence (CI) tests. The null is the number of LMC violations of a random
      node-permutation of the given graph. Our test can be interpreted as whether the given graph is significantly better
      than random in terms of the CIs it entails.
      To determine whether a given graph is falsifiable by our metric, we implement a second test, which reports whether
      given graph is "characteristic" enough in terms of the CIs it entails. For this, we compute how many of the random
      node permutations lie in the same Markov equivalence class (MEC) as the given graph and conclude that the given
      graph is falsifiable only if the fraction of permuted DAGs in the same MEC as the given graph is "reasonably" small.
  
      The returned EvaluationResult object has two attributes: `falsified` and `falsifiable`:
          `falsifiable`: The given graph lies in a different MEC than >= 1-`significance_level` of the permuted DAGs
          `falsified`: The given graph is falsifiable and violates fewer LMCs than >= 1-`significance_level` of the
                          permuted DAGs
  
      By default, we only run 1 / `significance_level` permutations as those are enough to falsify a graph with type I
      error probability `significance_level` at some given `significance_level`. If you are interested in a more exact
      estimate of the p-value or wish to plot a histogram to see how the given DAG compares to random node permutations,
      you should set `n_permutations` to some larger value (e.g. 100 or 1000). If `n_permutations=-1` we test on all
      n_nodes! permutations (the default if plot_histogram=True).
  
      Additionally, this method allows to return suggestions to the user (suggestions=True). This is done by testing for
      violations of causal minimality via `validate_cm`.
  
      Related paper:
          Eulig, E., Mastakouri, A. A., Blöbaum, P., Hardt, M., & Janzing, D. (2023).
          Toward Falsifying Causal Graphs Using a Permutation-Based Test.
          https://arxiv.org/abs/2305.09565
  
      :param causal_graph: A directed acyclic graph (DAG).
      :param data: Observations of variables in the DAG.
      :param suggestions: Provide suggestions to the user. At the moment the only source of suggestions comes from
                          validating causal minimality (using validate_cm).
      :param independence_test: Independence test to use for checking pairwise independencies.
      :param conditional_independence_test: Conditional independence test to use.
      :param significance_level: Significance level for the permutation test.
      :param significance_ci: Significance level for (conditional) independence tests.
      :param n_permutations: Number of permutations to perform. If -1 use all n_nodes! permutations.
      :param show_progress_bar: Whether to show progress bar over permutations.
      :param n_jobs: Number of jobs to use for parallel execution of (conditional) independence tests.
      :param plot_histogram: Plot histogram of results from permutation baseline.
      :param plot_kwargs: Additional plot arguments to be passed to plot_evaluation_results.
      :param allow_data_subset: If True, performs the evaluation even if data is only available for a subset of nodes.
                                     If False, raises an error if not all nodes have data available.
      :return: EvaluationResult
      """
      if not allow_data_subset and not set(
          [str(node) for node in causal_graph.nodes]
      ).issubset(set([str(col) for col in data.columns])):
          raise ValueError(
              "Did not find data for all nodes of the given graph! Make sure that the node names coincide "
              "with the column names in the data."
          )
  
      n_jobs = config.default_n_jobs if n_jobs is None else n_jobs
      show_progress_bar = (
          config.show_progress_bars
          if show_progress_bar is None
          else show_progress_bar
      )
      p_values_memory = _PValuesMemory()
  
      if n_permutations is None:
          n_permutations = int(1 / significance_level)
  
      if not plot_kwargs:
          plot_kwargs = {}
  
      methods = (
          partial(
              validate_lmc,
              independence_test=independence_test,
              conditional_independence_test=conditional_independence_test,
              significance_level=significance_ci,
              p_values_memory=p_values_memory,
              n_jobs=n_jobs,
          ),
          partial(validate_tpa, causal_graph_reference=causal_graph),
      )
  
      if suggestions:
          suggestion_methods = (
              partial(
                  validate_cm,
                  independence_test=independence_test,
                  conditional_independence_test=conditional_independence_test,
                  significance_level=significance_ci,
                  p_values_memory=p_values_memory,
                  n_jobs=n_jobs,
              ),
          )
      else:
          suggestion_methods = tuple()
  
      summary_given = run_validations(
          causal_graph,
          data,
          methods=methods + suggestion_methods,
      )
      summary_perm = _permutation_based(
          causal_graph,
          data,
          methods=methods,
          exclude_original_order=False,
          n_permutations=n_permutations,
          show_progress_bar=show_progress_bar,
      )
  
      summary = dict()
      validation_methods = set(summary_perm.keys()) - {
          FalsifyConst.PERM_GRAPHS
      }
      for m in validation_methods:
          summary[m] = dict()
  
          summary[m][FalsifyConst.PERM_VIOLATIONS] = [
              perm[FalsifyConst.N_VIOLATIONS]
              for perm in summary_perm[m]
          ]
          summary[m][FalsifyConst.GIVEN_VIOLATIONS] = summary_given[m][
              FalsifyConst.N_VIOLATIONS
          ]
          summary[m][FalsifyConst.N_TESTS] = summary_given[m][
              FalsifyConst.N_TESTS
          ]
          summary[m][FalsifyConst.F_PERM_VIOLATIONS] = [
              perm[FalsifyConst.N_VIOLATIONS]
              / max(1, perm[FalsifyConst.N_TESTS])
              for perm in summary_perm[m]
          ]
          summary[m][FalsifyConst.F_GIVEN_VIOLATIONS] = summary[m][
              FalsifyConst.GIVEN_VIOLATIONS
          ] / max(1, summary[m][FalsifyConst.N_TESTS])
          summary[m][FalsifyConst.P_VALUE] = sum(
              [
                  1
                  for perm in summary[m][FalsifyConst.F_PERM_VIOLATIONS]
                  if perm <= summary[m][FalsifyConst.F_GIVEN_VIOLATIONS]
              ]
          ) / len(summary[m][FalsifyConst.PERM_VIOLATIONS])
  
          if m != FalsifyConst.VALIDATE_TPA:
              # Append list of violations (node, non_desc) to get local information
              summary[m][
                  FalsifyConst.LOCAL_VIOLATION_INSIGHT
              ] = summary_given[m][FalsifyConst.P_VALUES]
  
      if FalsifyConst.VALIDATE_TPA in summary:
          summary[FalsifyConst.MEC] = [
              summary_perm[FalsifyConst.PERM_GRAPHS][i]
              for i, v in enumerate(
                  summary[FalsifyConst.VALIDATE_TPA][
                      FalsifyConst.PERM_VIOLATIONS
                  ]
              )
              if v == 0
          ]
  
      result = EvaluationResult(
          summary=summary,
          significance_level=significance_level,
          suggestions={
              m: summary_given[m]
              for m in summary_given
              if m not in validation_methods
          },
      )
      if plot_histogram and result.can_evaluate:
          plot_evaluation_results(result, **plot_kwargs)
      return result
  
imports: import warnings
  from dataclasses import dataclass, field
  from enum import Enum, auto
  from functools import partial
  from inspect import getfullargspec
  from itertools import permutations
  from typing import Any, Callable, Dict, FrozenSet, List, Optional, Set, Tuple, Union
  import matplotlib.colors
  import matplotlib.pyplot
  import networkx
  import numpy
  import pandas
  from joblib import Parallel, delayed
  from tqdm import tqdm
  import dowhy.gcm.config
  from dowhy.gcm.independence_test import kernel_based
  from dowhy.gcm.util import plot
  from dowhy.gcm.util.general import set_random_seed
  from dowhy.graph import DirectedGraph, get_ordered_predecessors
label_desc: Use image node_id 6 for calling a global function with example usage: falsify_graph(causal_graph, data, suggestions, independence_test, conditional_independence_test, significance_level, significance_ci, n_permutations, show_progress_bar, n_jobs, plot_histogram, plot_kwargs, allow_data_subset) and returns: result