code: def generalised_cov_based(
      X: np.ndarray,
      Y: np.ndarray,
      Z: Optional[np.ndarray] = None,
      prediction_model_X: Union[
          AssignmentQuality, Callable[[], PredictionModel]
      ] = AssignmentQuality.BETTER,
      prediction_model_Y: Union[
          AssignmentQuality, Callable[[], PredictionModel]
      ] = AssignmentQuality.BETTER,
  ):
      """(Conditional) independence test based on the Generalised Covariance Measure.
  
      Note:
      - Currently, only univariate and continuous X and Y are supported.
      - Residuals are based on the training data.
      - The relationships need to be non-deterministic, i.e., the residuals cannot be constant!
  
      See
      - R. D. Shah and J Peters. *The hardness of conditional independence testing and the generalised covariance measure*, The Annals of Statistics 48(3), 2018
      for more details.
  
      :param X: Data matrix for observations from X.
      :param Y: Data matrix for observations from Y.
      :param Z: Optional data matrix for observations from Z. This is the conditional variable.
      :param prediction_model_X: Either a model class that will be used as prediction model for regressing X on Z
                                 (e.g., a linear regressor) or an AssignmentQuality for automatically selecting
                                 a model.
      :param prediction_model_Y: Either a model class that will be used as prediction model for regressing X on Z
                                 (e.g., a linear regressor) or an AssignmentQuality for automatically selecting
                                 a model.
      :return The p-value for the null hypothesis that X and Y are independent (given Z).
      """
      X, Y = shape_into_2d(X, Y)
  
      if is_categorical(X) or is_categorical(Y):
          raise ValueError("X and Y need to be continuous variables!")
  
      if X.shape[1] > 1 or Y.shape[1] > 1:
          raise ValueError("X and Y need to be one dimensional!")
  
      if X.shape[0] != Y.shape[0]:
          raise ValueError(
              "X and Y need to have the same number of rows!"
          )
  
      if Z is None:
          residuals_xz = X - np.mean(X)
          residuals_yz = Y - np.mean(Y)
      else:
          if Z.shape[0] != X.shape[0]:
              raise ValueError(
                  "Z, X and Y need to have the same number of rows!"
              )
  
          model_x = _create_model(Z, X, prediction_model_X)
          model_y = _create_model(Z, Y, prediction_model_Y)
  
          model_x.fit(Z, X)
          model_y.fit(Z, Y)
  
          residuals_xz = X - model_x.predict(Z)
          residuals_yz = Y - model_y.predict(Z)
  
      if np.var(residuals_yz) == 0 or np.var(residuals_xz) == 0:
          raise ValueError("Residuals cannot be constant!")
  
      # Calculate Ri, the product of the residuals
      residual_products = np.multiply(residuals_xz, residuals_yz)
  
      # Standard deviation of the residuals
      residual_std = np.std(residual_products)
  
      if residual_std == 0:
          return 1
  
      test_statistic = (
          np.sum(residual_products) / np.sqrt(X.shape[0])
      ) / residual_std
  
      return stats.norm.sf(abs(test_statistic)) * 2
  
file_path: dowhy/dowhy/gcm/independence_test/generalised_cov_measure.py
imports: from typing import Callable, Optional, Union
  import numpy
  from scipy import stats
  from dowhy.gcm.auto import AssignmentQuality, select_model
  from dowhy.gcm.ml import PredictionModel
  from dowhy.gcm.util.general import is_categorical, shape_into_2d
label_desc: Use image node_id 1 for calling a global function with example usage: generalised_cov_based(X, Y, Z, prediction_model_X, prediction_model_Y) and returns: unknown, int