# Path: sdcit/utils.py
# 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 cythonize(*matrices):
#     return tuple(np.ascontiguousarray(matrix, dtype=np.float64) for matrix in matrices)
# 
# 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 centering(M: np.ndarray) -> Union[None, np.ndarray]:
#     """Matrix Centering"""
#     if M is None:
#         return None
#     n = len(M)
#     H = np.eye(n) - 1 / n
#     return H @ M @ H


import numpy as np
import scipy.stats
from typing import List, Tuple
from sdcit.cython_impl.cy_sdcit import cy_hsic
from sdcit.utils import p_value_of, cythonize, random_seeds, centering

    test_statistics = HSIC_stat(Kc, Lc)

    def shuffled():
        perm = np.random.permutation(len(K))
        return Lc[np.ix_(perm, perm)]

    null_distribution = [HSIC_stat(Kc, shuffled()) for _ in range(num_boot)]

    return p_value_of(test_statistics, null_distribution)


def c_HSIC(K: np.ndarray, L: np.ndarray, size_of_null_sample=1000, with_null=False, seed=None, n_jobs=1):
    if seed is not None:
        np.random.seed(seed)

    K, L = centering(K), centering(L)
    K, L = cythonize(K, L)
    raw_null = np.zeros((size_of_null_sample,), dtype='float64')
    test_statistic = np.zeros((1,), dtype='float64')

    # run SDCIT
    cy_hsic(K, L, size_of_null_sample, random_seeds(), n_jobs, test_statistic, raw_null)

    # post-process outputs
    test_statistic = test_statistic[0]

    if with_null:
        return test_statistic, p_value_of(test_statistic, raw_null), raw_null
    else:

# Path: sdcit/utils.py
# 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 cythonize(*matrices):
#     return tuple(np.ascontiguousarray(matrix, dtype=np.float64) for matrix in matrices)
# 
# 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 centering(M: np.ndarray) -> Union[None, np.ndarray]:
#     """Matrix Centering"""
#     if M is None:
#         return None
#     n = len(M)
#     H = np.eye(n) - 1 / n
#     return H @ M @ H


# Path: sdcit/hsic.py
import numpy as np
import scipy.stats
from typing import List, Tuple
from sdcit.cython_impl.cy_sdcit import cy_hsic
from sdcit.utils import p_value_of, cythonize, random_seeds, centering


    test_statistics = HSIC_stat(Kc, Lc)

    def shuffled():
        perm = np.random.permutation(len(K))
        return Lc[np.ix_(perm, perm)]

    null_distribution = [HSIC_stat(Kc, shuffled()) for _ in range(num_boot)]

    return p_value_of(test_statistics, null_distribution)


def c_HSIC(K: np.ndarray, L: np.ndarray, size_of_null_sample=1000, with_null=False, seed=None, n_jobs=1):
    if seed is not None:
        np.random.seed(seed)

    K, L = centering(K), centering(L)
    K, L = cythonize(K, L)
    raw_null = np.zeros((size_of_null_sample,), dtype='float64')
    test_statistic = np.zeros((1,), dtype='float64')

    # run SDCIT
    cy_hsic(K, L, size_of_null_sample, random_seeds(), n_jobs, test_statistic, raw_null)

    # post-process outputs
    test_statistic = test_statistic[0]

    if with_null:
        return test_statistic, p_value_of(test_statistic, raw_null), raw_null
    else:

        return test_statistic, p_value_of(test_statistic, raw_null)