def kernel(self, X, Y=None):
        
        if not type(X) is numpy.ndarray:
            raise TypeError("X must be numpy array")
        
        if not len(X.shape) == 2:
            raise ValueError("X must be 2D numpy array")
        
        if not X.dtype == numpy.bool8:
            raise ValueError("X must be boolean numpy array")
        
        if not Y is None:
            if not type(Y) is numpy.ndarray:
                raise TypeError("Y must be None or numpy array")
            
            if not len(Y.shape) == 2:
                raise ValueError("Y must be None or 2D numpy array")
            
            if not Y.dtype == numpy.bool8:
                raise ValueError("Y must be boolean numpy array")
        
            if not X.shape[1] == Y.shape[1]:
                raise ValueError("X and Y must have same dimension if Y is not None")
        
        # un-normalise normalised hamming distance in both cases
        if Y is None:
            K = tanh(self.gamma) ** squareform(pdist(X, 'hamming') * X.shape[1])
        else:
            K = tanh(self.gamma) ** (cdist(X, Y, 'hamming') * X.shape[1])
            
        return K
Computes the hypercube kernel k(x,y)=tanh(gamma)^d(x,y), where d is the
dataset/ETHPy150Open karlnapf/kameleon-mcmc/kameleon_mcmc/kernel/HypercubeKernel.py/HypercubeKernel.kernel