docstr: Randomly permute the nodes of a given causal graph while keeping the underlying graph structure the same.
  :param causal_graph: A directed acyclic graph (DAG).
  :param exclude_original_order: Do not return the original order.
  :param n_permutations: Return a generator with n_permutations permutations. If n_permutations = -1 (default),
          we return all n_nodes! - int(exclude_orig) permutations.
  :return: Copy of causal_graph with nodes randomly permuted.
docstr_tok: ["Randomly","permute","the","nodes","of","a","given","causal","graph","while","keeping","the","underlying","graph","structure","the","same",".",":","param","causal_graph",":","A","directed","acyclic","graph","(","DAG",")",".",":","param","exclude_original_order",":","Do","not","return","the","original","order",".",":","param","n_permutations",":","Return","a","generator","with","n_permutations","permutations",".","If","n_permutations","=","-1","(","default",")",",","we","return","all","n_nodes","!","-","int","(","exclude_orig",")","permutations",".",":","return",":","Copy","of","causal_graph","with","nodes","randomly","permuted","."]
code: def __init__(
      self,
      causal_graph: DirectedGraph,
      exclude_original_order: bool,
      n_permutations: int,
  ):
      """
      Randomly permute the nodes of a given causal graph while keeping the underlying graph structure the same.
      :param causal_graph: A directed acyclic graph (DAG).
      :param exclude_original_order: Do not return the original order.
      :param n_permutations: Return a generator with n_permutations permutations. If n_permutations = -1 (default),
              we return all n_nodes! - int(exclude_orig) permutations.
      :return: Copy of causal_graph with nodes randomly permuted.
      """
      self.causal_graph = causal_graph
      self.exclude_original_order = exclude_original_order
      self.n_permutations = n_permutations
      self.max_perms = np.math.factorial(
          self.causal_graph.number_of_nodes()
      ) - int(self.exclude_original_order)
  
      if n_permutations == -1 or n_permutations > self.max_perms:
          self.it = self.iter_all_permutations()
          self.length = self.max_perms
          if self.length > 2**63 - 1:
              raise ValueError(
                  f"Too many permutations specified. Did you accidently set 'n_permutations'=-1 for a "
                  f"large (>20 nodes) graph? "
                  f"Given graph has {causal_graph.number_of_nodes()} nodes."
              )
      else:
          self.it = self.iter_random_permutations()
          self.length = self.n_permutations
  
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 1 to create a new _PermuteNodes object  with example: obj = _PermuteNodes(causal_graph, exclude_original_order, n_permutations)