# Path: sdcit/utils.py
# def K2D(K: Union[None, np.ndarray]) -> np.ndarray:
#     """An RKHS distance matrix given a kernel matrix
# 
#     A distance matrix D of the same size of the given kernel matrix K
#      :math:`d^2(i,j)=k(i,i)+k(j,j)-2k(i,j)`.
#     """
#     if K is None:
#         return None
# 
#     Kd = repmat(diag(K).reshape((len(K), 1)), 1, len(K))
#     temp = Kd + Kd.transpose() - 2 * K
#     min_val = np.min(temp)
#     if min_val < 0.0:
#         if min_val < -1e-15:
#             warnings.warn('K2D: negative values will be treated as zero. Observed: {}'.format(min_val))
#         temp *= (temp > 0)
#     return np.sqrt(temp)
# 
# def p_value_of(val: float, data: typing.Iterable) -> float:
#     """The percentile of a value given a data"""
# 
#     data = np.sort(data)
#     return float(1 - np.searchsorted(data, val, side='right') / len(data))
# 
# def random_seeds(n=None):
#     """Random seeds of given size or a random seed if n is None"""
#     if n is None:
#         return np.random.randint(np.iinfo(np.int32).max)
#     else:
#         return [np.random.randint(np.iinfo(np.int32).max) for _ in range(n)]
# 
# def cythonize(*matrices):
#     return tuple(np.ascontiguousarray(matrix, dtype=np.float64) for matrix in matrices)


from typing import Tuple
from sdcit.cython_impl.cy_sdcit import cy_sdcit, cy_split_permutation, cy_dense_permutation
from sklearn.linear_model import LinearRegression
from sdcit.utils import K2D, p_value_of, random_seeds, cythonize
import numpy as np
import numpy.ma as ma
        Lee, S., Honavar, V. (2017). Self-Discrepancy Conditional Independence Test.
        In Proceedings of the Thirty-third Conference on Uncertainty in Artificial Intelligence. Corvallis, Oregon: AUAI Press.
    """
    if seed is not None:
        np.random.seed(seed)

    if Dz is None:
        Dz = K2D(Kz)

    if to_shuffle:
        Kx, Ky, Kz, Dz = shuffling(seed, Kx, Ky, Kz, Dz)  # categorical Z may yield an ordered 'block' matrix and it may harm permutation.

    Kxz = Kx * Kz

    test_statistic, error_statistic, mask, _ = MMSD(Ky, Kz, Kxz, Dz)
    mask, Pidx = mask_and_perm(penalized_distance(Dz, mask))

    # avoid permutation between already permuted pairs.
    mmsd_distr_under_null, error_distr_under_null = emp_MMSD(Kxz, Ky[np.ix_(Pidx, Pidx)], Kz, penalized_distance(Dz, mask), size_of_null_sample)

    if adjust:
        fix_null, fix_test_statistic = adjust_errors(error_distr_under_null, mmsd_distr_under_null, error_statistic, test_statistic)
        fix_null = fix_null - fix_null.mean()
    else:
        fix_null = mmsd_distr_under_null - mmsd_distr_under_null.mean()
        fix_test_statistic = test_statistic

    if with_null:
        return fix_test_statistic, p_value_of(fix_test_statistic, fix_null), fix_null
    else:

# Path: sdcit/utils.py
# def K2D(K: Union[None, np.ndarray]) -> np.ndarray:
#     """An RKHS distance matrix given a kernel matrix
# 
#     A distance matrix D of the same size of the given kernel matrix K
#      :math:`d^2(i,j)=k(i,i)+k(j,j)-2k(i,j)`.
#     """
#     if K is None:
#         return None
# 
#     Kd = repmat(diag(K).reshape((len(K), 1)), 1, len(K))
#     temp = Kd + Kd.transpose() - 2 * K
#     min_val = np.min(temp)
#     if min_val < 0.0:
#         if min_val < -1e-15:
#             warnings.warn('K2D: negative values will be treated as zero. Observed: {}'.format(min_val))
#         temp *= (temp > 0)
#     return np.sqrt(temp)
# 
# def p_value_of(val: float, data: typing.Iterable) -> float:
#     """The percentile of a value given a data"""
# 
#     data = np.sort(data)
#     return float(1 - np.searchsorted(data, val, side='right') / len(data))
# 
# def random_seeds(n=None):
#     """Random seeds of given size or a random seed if n is None"""
#     if n is None:
#         return np.random.randint(np.iinfo(np.int32).max)
#     else:
#         return [np.random.randint(np.iinfo(np.int32).max) for _ in range(n)]
# 
# def cythonize(*matrices):
#     return tuple(np.ascontiguousarray(matrix, dtype=np.float64) for matrix in matrices)


# Path: sdcit/sdcit_mod.py
from typing import Tuple
from sdcit.cython_impl.cy_sdcit import cy_sdcit, cy_split_permutation, cy_dense_permutation
from sklearn.linear_model import LinearRegression
from sdcit.utils import K2D, p_value_of, random_seeds, cythonize
import numpy as np
import numpy.ma as ma

        Lee, S., Honavar, V. (2017). Self-Discrepancy Conditional Independence Test.
        In Proceedings of the Thirty-third Conference on Uncertainty in Artificial Intelligence. Corvallis, Oregon: AUAI Press.
    """
    if seed is not None:
        np.random.seed(seed)

    if Dz is None:
        Dz = K2D(Kz)

    if to_shuffle:
        Kx, Ky, Kz, Dz = shuffling(seed, Kx, Ky, Kz, Dz)  # categorical Z may yield an ordered 'block' matrix and it may harm permutation.

    Kxz = Kx * Kz

    test_statistic, error_statistic, mask, _ = MMSD(Ky, Kz, Kxz, Dz)
    mask, Pidx = mask_and_perm(penalized_distance(Dz, mask))

    # avoid permutation between already permuted pairs.
    mmsd_distr_under_null, error_distr_under_null = emp_MMSD(Kxz, Ky[np.ix_(Pidx, Pidx)], Kz, penalized_distance(Dz, mask), size_of_null_sample)

    if adjust:
        fix_null, fix_test_statistic = adjust_errors(error_distr_under_null, mmsd_distr_under_null, error_statistic, test_statistic)
        fix_null = fix_null - fix_null.mean()
    else:
        fix_null = mmsd_distr_under_null - mmsd_distr_under_null.mean()
        fix_test_statistic = test_statistic

    if with_null:
        return fix_test_statistic, p_value_of(fix_test_statistic, fix_null), fix_null
    else:

        return fix_test_statistic, p_value_of(fix_test_statistic, fix_null)