jiahuimbzuai/CoQuIR huggingface dataset:
//  [python]
def naiive_subspace_detector(point_list, grade,
                             point_cost_threshold=0.1,
                             flat_flag=True, n_tests=1000):
    """
    Given a point cloud extract objects of the given grade
    This only works for conformal algebras at the moment
    """
    layout = point_list[0].layout
    if not layout.isconformal:
        raise ValueError('The naiive_subspace_detector only operates on conformal algebras at the moment')
    einf = layout.einf

    def sample_objects(point_list, grade, n_tests, flat_flag=True):
        if flat_flag:
            n_sample_objects = grade - 1
        else:
            n_sample_objects = grade

        # How many combos are there
        nchoosek = scipy.special.comb(len(point_list), n_sample_objects)

        # Get a combo generator
        combos = itertools.combinations(point_list, n_sample_objects)

        # Sample from the generator
        n_samples = int(min([n_tests, nchoosek]))
        sampled_objects_list = random.sample(list(combos), n_samples)

        # Wedge the results
        output_list = []
        for i in range(n_samples):
            print(i, flush=True)
            sampled_objects = sampled_objects_list[i]
            wedged_points = functools.reduce(lambda x, y: x ^ y, sampled_objects)
            output_object = wedged_points
            if flat_flag:
                output_object = output_object ^ einf
            final_object = (output_object).normal()
            output_list.append(final_object)
        return output_list

    def associate_points_with_objects(point_list, object_list, point_cost_threshold=0.1):
        # Check how close all the points are to each object
        point_associations = []
        for obj in object_list:
            this_obj_association = []
            for i, p in enumerate(point_list):
                if abs(obj ^ p) < point_cost_threshold:
                    this_obj_association.append(i)
            point_associations.append(this_obj_association)
        return point_associations

    print('SAMPLING', flush=True)
    object_list = sample_objects(point_list, grade, n_tests, flat_flag=flat_flag)

    print('ASSOCIATING', flush=True)
    point_associations = associate_points_with_objects(point_list,
                                                       object_list,
                                                       point_cost_threshold=point_cost_threshold)
    return point_associations, object_list
//  [python]
def expected_intersection_interpretable(n, dvals, hamm_radius, r, weight_type=None):
    
    if r is None: 
        r = 1.0
    
    perc_addresses_w_neurons = np.log(float(r)) - np.log(2.0**n)
    res = []
    for dval in dvals:

        possible_addresses = 0
        for a in np.arange(n-hamm_radius-(dval//2),n+0.1-dval):

            # solve just for b then c is determined. 
            bvals = np.arange(np.maximum(0,n-hamm_radius-a), dval-(n-hamm_radius-a)+0.1) # +0.1 to ensure that the value here is represented.
            #print(a, 'b values', bvals)
            if len(bvals)==0:
                continue
                
            if weight_type == "Linear":
                # linear weighting from the read and write operations. 
                weighting = ((a+bvals)/n) * ( (a+(dval-bvals))/n )
            if weight_type == "Expo":
                # linear weighting from the read and write operations. 
                weighting = np.exp(-0.01*(n-(a+bvals))) * np.exp(-0.01*(n-(a+(dval-bvals))))
            elif not weight_type: 
                weighting = 1

            possible_addresses += s.comb(n-dval,a)*(weighting*s.comb(dval,bvals)).sum()
        expected_intersect = perc_addresses_w_neurons + np.log(possible_addresses)
        res.append(np.exp(expected_intersect))
    return np.asarray(res)
//  [python]
def expected_intersection_interpretable(n, dvals, hamm_radius, r, weight_type=None):
    
    if r is None: 
        r = 1.0
    
    perc_addresses_w_neurons = np.log(float(r)) - np.log(2.0**n)
    res = []
    for dval in dvals:

        possible_addresses = 0
        for a in np.arange(n-hamm_radius-(dval//2),n+0.1-dval):

            # solve just for b then c is determined. 
            bvals = np.arange(np.maximum(0,n-hamm_radius-a), dval-(n-hamm_radius-a)+0.1) # +0.1 to ensure that the value here is represented.
            #print(a, 'b values', bvals)
            if len(bvals)==0:
                continue
                
            if weight_type == "Linear":
                # linear weighting from the read and write operations. 
                weighting = ((a+bvals)/n) * ( (a+(dval-bvals))/n )
            if weight_type == "Expo":
                # linear weighting from the read and write operations. 
                weighting = np.exp(-0.01*(n-(a+bvals))) * np.exp(-0.01*(n-(a+(dval-bvals))))
            elif not weight_type: 
                weighting = 1

            possible_addresses += comb(n-dval,a)*(weighting*comb(dval,bvals)).sum()
        expected_intersect = perc_addresses_w_neurons + np.log(possible_addresses)
        res.append(np.exp(expected_intersect))
    return np.asarray(res)
//  [python]
def _munp(self, n, c):
        k = arange(0, n+1)
        vals = 1.0/c**n * np.sum(
            s.comb(n, k) * (-1)**k * special.gamma(c*k + 1),
            axis=0)
        return where(c*n > -1, vals, inf)
//  [python]
def _munp(self, n, c):
        k = arange(0, n+1)
        vals = 1.0/c**n * np.sum(
            comb(n, k) * (-1)**k * special.gamma(c*k + 1),
            axis=0)
        return where(c*n > -1, vals, inf)
//  [python]
def expected_intersection_lune(n, dvals, hamm_radius, r):
    # This equation gives the same results as the one we derive and present in the paper. It was introduced in the SDM book and runs a bit faster. 
    """
    Computes the fraction of the space that exists in the circle intersection using the Lune equation. 
    
    args::
    n = space dimension
    dvals = Hamm dist between circle centers
    hamm_radius = hamming distance radius each circle uses
    r = number of neurons
    
    hard_mem_places = turns the fraction of the space in the 
    expected number of neurons
    that exist in this fraction. 
    
    ------------
    
    returns:: 
    res = list of floats for fraction of the space
    """
    
    #ensure all are ints: 
    n = int(n)
    hamm_radius = int(hamm_radius)
    
    if r is not None: 
        r = int(r)
        perc_addresses_w_neurons = r/(2**n) 
    else: 
        perc_addresses_w_neurons = 1.0
    
    res = []
    area = 0
    # compute size of circle
    for i in range(hamm_radius+1):
        area += s.comb(n,i)

    for d in dvals: 
        # compute lune
        d = int(d)
        lune = 0
        for i in range(d):
            j = i+1
            if j%2==0:
                continue
            lune+= s.comb(j-1, (j-1)/2)*s.comb(n-j, hamm_radius-((j-1)/2))
        intersect = area - lune
        #print(d, intersect, area, lune, perc_addresses_w_neurons)
        expected_intersect = np.log(intersect)+np.log(perc_addresses_w_neurons)
        res.append(np.exp(expected_intersect))
        
    res = np.asarray(res)
    res = np.nan_to_num(res, nan=0.0)
    return res
//  [python]
def expected_intersection_lune(n, dvals, hamm_radius, r):
    # This equation gives the same results as the one we derive and present in the paper. It was introduced in the SDM book and runs a bit faster. 
    """
    Computes the fraction of the space that exists in the circle intersection using the Lune equation. 
    
    args::
    n = space dimension
    dvals = Hamm dist between circle centers
    hamm_radius = hamming distance radius each circle uses
    r = number of neurons
    
    hard_mem_places = turns the fraction of the space in the 
    expected number of neurons
    that exist in this fraction. 
    
    ------------
    
    returns:: 
    res = list of floats for fraction of the space
    """
    
    #ensure all are ints: 
    n = int(n)
    hamm_radius = int(hamm_radius)
    
    if r is not None: 
        r = int(r)
        perc_addresses_w_neurons = r/(2**n) 
    else: 
        perc_addresses_w_neurons = 1.0
    
    res = []
    area = 0
    # compute size of circle
    for i in range(hamm_radius+1):
        area += comb(n,i)

    for d in dvals: 
        # compute lune
        d = int(d)
        lune = 0
        for i in range(d):
            j = i+1
            if j%2==0:
                continue
            lune+= comb(j-1, (j-1)/2)*comb(n-j, hamm_radius-((j-1)/2))
        intersect = area - lune
        #print(d, intersect, area, lune, perc_addresses_w_neurons)
        expected_intersect = np.log(intersect)+np.log(perc_addresses_w_neurons)
        res.append(np.exp(expected_intersect))
        
    res = np.asarray(res)
    res = np.nan_to_num(res, nan=0.0)
    return res
//  [python]
def __call__(self, n, k):
        if not isinstance(n, int):
            n = int(n)
        if not isinstance(k, int):
            k = int(k)

        res = 1.0
        if n < 0 or k < 0:
            return 0.0

        if k == 0:
            return res

        if (n - k) < k:
            return s.comb(n, n - k)

        for ix in xrange(k):
            res = (res * (n - ix)) / (k - ix)

        return res
//  [python]
def __call__(self, n, k):
        if not isinstance(n, int):
            n = int(n)
        if not isinstance(k, int):
            k = int(k)

        res = 1.0
        if n < 0 or k < 0:
            return 0.0

        if k == 0:
            return res

        if (n - k) < k:
            return scipy.special.comb(n, n - k)

        for ix in xrange(k):
            res = (res * (n - ix)) / (k - ix)

        return res
//  [python]
def SDM_Interpretable(params, dvals, thresholds, title=None, label_prefix='ham='):
    """Same as the SDM lune equation in results. Equation was inspired by Jaeckel's SDM Hyperplane but applied to the SDM setting with binary vectors and optimized by working out lower and upper bounds to avoid using a CSP. This equation is much more interpretable than the Lune one used in the SDM Appendix B.
    
    See paper for the constraints and bounds explained."""
    
    perc_addresses_w_neurons = np.log(params.r) - np.log(2.0**params.n)

    for thresh in thresholds:
        res = []
        for dval in dvals:

            possible_addresses = 0
            #print('range of a vals', np.arange(params.n-thresh-(dval//2),params.n+1-dval))
            for a in np.arange(params.n-thresh-(dval//2),params.n+0.1-dval):

                # solve just for b then c is determined. 
                bvals = np.arange(np.maximum(0,params.n-thresh-a), dval-(params.n-thresh-a)+0.1) # +0.1 to ensure that the value here is represented.
                #print(a, 'b values', bvals)
                if len(bvals)==0:
                    continue

                possible_addresses += s.comb(params.n-dval,a)*s.comb(dval,bvals).sum()
            expected_intersect = perc_addresses_w_neurons + np.log(possible_addresses)
            res.append(np.exp(expexcted_intersect))
        res =np.asarray(res)
        plot_line(dvals, res, label_prefix, thresh, params.norm)
        
        if params.fit_beta_and_plot_attention:
            fit_beta_res, beta = fit_beta_regression(params.n, dvals, res)
            plot_line(dvals, fit_beta_res, 'fit_beta | '+label_prefix, thresh, params.norm)
    
    if title: # else can call "label plot separately"
        label_plot(title, params.norm)
    return res
//  [python]
def SDM_Interpretable(params, dvals, thresholds, title=None, label_prefix='ham='):
    """Same as the SDM lune equation in results. Equation was inspired by Jaeckel's SDM Hyperplane but applied to the SDM setting with binary vectors and optimized by working out lower and upper bounds to avoid using a CSP. This equation is much more interpretable than the Lune one used in the SDM Appendix B.
    
    See paper for the constraints and bounds explained."""
    
    perc_addresses_w_neurons = np.log(params.r) - np.log(2.0**params.n)

    for thresh in thresholds:
        res = []
        for dval in dvals:

            possible_addresses = 0
            #print('range of a vals', np.arange(params.n-thresh-(dval//2),params.n+1-dval))
            for a in np.arange(params.n-thresh-(dval//2),params.n+0.1-dval):

                # solve just for b then c is determined. 
                bvals = np.arange(np.maximum(0,params.n-thresh-a), dval-(params.n-thresh-a)+0.1) # +0.1 to ensure that the value here is represented.
                #print(a, 'b values', bvals)
                if len(bvals)==0:
                    continue

                possible_addresses += comb(params.n-dval,a)*comb(dval,bvals).sum()
            expected_intersect = perc_addresses_w_neurons + np.log(possible_addresses)
            res.append(np.exp(expexcted_intersect))
        res =np.asarray(res)
        plot_line(dvals, res, label_prefix, thresh, params.norm)
        
        if params.fit_beta_and_plot_attention:
            fit_beta_res, beta = fit_beta_regression(params.n, dvals, res)
            plot_line(dvals, fit_beta_res, 'fit_beta | '+label_prefix, thresh, params.norm)
    
    if title: # else can call "label plot separately"
        label_plot(title, params.norm)
    return res
//  [python]
def mult(N, q):
	return s.comb(q+N-1, q, exact = True)
//  [python]
def mult(N, q):
	return sp.special.comb(q+N-1, q, exact = True)
//  [python]
def numVariablesDegree(d, n):
    """
    Computes number of monomials of degree d in n variables.

    Args:
      d (int): degree of monomials
      n (int): number of variables

    Returns:
      int: number of monomials
    """

    return s.comb(d + n - 1, n - 1, exact = True)
//  [python]
def numVariablesDegree(d, n):
    """
    Computes number of monomials of degree d in n variables.

    Args:
      d (int): degree of monomials
      n (int): number of variables

    Returns:
      int: number of monomials
    """

    return scipy.special.comb(d + n - 1, n - 1, exact = True)
//  [python]
def numVariablesUpDegree(d, n):
    """
    Computes number of monomials of degrees up to d in n variables.

    Args:
      d (int): maximal degree of monomials
      n (int): number of variables

    Returns:
      int: number of monomials
    """

    return scipy.misc.comb(d + n, n, exact = True)
//  [python]
def numVariablesUpDegree(d, n):
    """
    Computes number of monomials of degrees up to d in n variables.

    Args:
      d (int): maximal degree of monomials
      n (int): number of variables

    Returns:
      int: number of monomials
    """

    return scipy.special.comb(d + n, n, exact = True)
//  [python]
def _create_filter_distribution(
        filter_size_min: int, filter_size_max: int, alpha: float, beta: float
    ) -> Tuple[List[int], Union[List[float], np.ndarray]]:
        n = (filter_size_max - filter_size_min) // 2 + 1
        if n < 2:
            return [filter_size_min], np.asarray([1.0], dtype=np.float32)
        filter_sizes = []
        filter_probs = []
        for k in range(n):
            filter_sizes.append(filter_size_min + 2 * k)
            filter_probs.append(
                scipy.special.comb(n, k, exact=False) * scipy.special.beta(alpha + k, n - k + beta)
            )
        np_filter_probs = np.asarray(filter_probs, dtype=np.float32)
        np_filter_probs = filter_probs / np_filter_probs.sum()
        return filter_sizes, np_filter_probs
//  [python]
def _create_filter_distribution(
        filter_size_min: int, filter_size_max: int, alpha: float, beta: float
    ) -> Tuple[List[int], Union[List[float], np.ndarray]]:
        n = (filter_size_max - filter_size_min) // 2 + 1
        if n < 2:
            return [filter_size_min], np.asarray([1.0], dtype=np.float32)
        filter_sizes = []
        filter_probs = []
        for k in range(n):
            filter_sizes.append(filter_size_min + 2 * k)
            filter_probs.append(
                scipy.special.comb(n, k) * scipy.special.beta(alpha + k, n - k + beta)
            )
        np_filter_probs = np.asarray(filter_probs, dtype=np.float32)
        np_filter_probs = filter_probs / np_filter_probs.sum()
        return filter_sizes, np_filter_probs
//  [python]
def feature_not_exact(m, n_combinations=200, weight_zero_m=10 ** 6):
    # Find weights for given number of features
    n_features = range(1, m)
    n = [scipy.misc.comb(m, n_element) for n_element in n_features]
    w = [shapley_weights(m, n[i], n_features[i]) * n[i] for i in range(len(n))]
    p = [x / sum(w) for x in w]

    # Sample number of chosen features
    X_list = random.choices(n_features, p, k=n_combinations)
    X_list.insert(0, 0)
    X_list.append(m)
    X = pd.DataFrame(X_list, columns=['n_features'])

    # Sample specific set of features
    X = X.sort_values(by=['n_features'], ignore_index=True)
    feature_sample = []
    # TODO This is written in c++ for shapr, probably much faster, should look into that
    for value in X['n_features']:
        # feature_sample.append(random.choices(n_features, k=value))
        feature_sample.append(sorted(random.sample(range(m), value)))

    # Get number of occurrences and duplicated rows
    r = helper_feature(m, feature_sample)
    X['is_duplicate'] = r['duplicated']

    # When we sample combinations the Shapley weight is equal
    # to the frequency of the given combination
    X['shapley_weight'] = r['sample_frequency']

    # Populate table and remove duplicated rows
    X['features'] = feature_sample

    if True in X['is_duplicate'].values:
        X = X[X.is_duplicate == False]

    del X['is_duplicate']

    # Add shapley weight and number of combinations
    X['shapley_weight'].iloc[[0, -1]] = weight_zero_m
    X['N'] = 1

    # TODO does not seem like r code uses p at all? It just removes it right after... Therefore I don't include it

    X = X.reset_index(drop=True)
    N = []
    P = []
    for item in X['n_features']:
        if item == 0 or item == 10:
            N.append(1)
            P.append(None)
        else:
            N.append(n[item-1])
            P.append(p[item-1])
    X['N'] = N
    X['p'] = P

    # Set column order
    X['id_combination'] = range(len(X))
    X = X[['id_combination', 'features', 'n_features', 'N', 'shapley_weight', 'p']]

    return X
//  [python]
def feature_not_exact(m, n_combinations=200, weight_zero_m=10 ** 6):
    # Find weights for given number of features
    n_features = range(1, m)
    n = [scipy.special.comb(m, n_element, exact=True) for n_element in n_features]
    w = [shapley_weights(m, n[i], n_features[i]) * n[i] for i in range(len(n))]
    p = [x / sum(w) for x in w]

    # Sample number of chosen features
    X_list = random.choices(n_features, p, k=n_combinations)
    X_list.insert(0, 0)
    X_list.append(m)
    X = pd.DataFrame(X_list, columns=['n_features'])

    # Sample specific set of features
    X = X.sort_values(by=['n_features'], ignore_index=True)
    feature_sample = []
    # TODO This is written in c++ for shapr, probably much faster, should look into that
    for value in X['n_features']:
        # feature_sample.append(random.choices(n_features, k=value))
        feature_sample.append(sorted(random.sample(range(m), value)))

    # Get number of occurrences and duplicated rows
    r = helper_feature(m, feature_sample)
    X['is_duplicate'] = r['duplicated']

    # When we sample combinations the Shapley weight is equal
    # to the frequency of the given combination
    X['shapley_weight'] = r['sample_frequency']

    # Populate table and remove duplicated rows
    X['features'] = feature_sample

    if True in X['is_duplicate'].values:
        X = X[X.is_duplicate == False]

    del X['is_duplicate']

    # Add shapley weight and number of combinations
    X['shapley_weight'].iloc[[0, -1]] = weight_zero_m
    X['N'] = 1

    # TODO does not seem like r code uses p at all? It just removes it right after... Therefore I don't include it

    X = X.reset_index(drop=True)
    N = []
    P = []
    for item in X['n_features']:
        if item == 0 or item == 10:
            N.append(1)
            P.append(None)
        else:
            N.append(n[item-1])
            P.append(p[item-1])
    X['N'] = N
    X['p'] = P

    # Set column order
    X['id_combination'] = range(len(X))
    X = X[['id_combination', 'features', 'n_features', 'N', 'shapley_weight', 'p']]

    return X
//  [python]
def binom_coeffs(n):
    return s.comb(n, np.arange(n + 1))
//  [python]
def binom_coeffs(n):
    return scipy.special.comb(n, np.arange(n + 1))
//  [python]
def from_bernstein_basis(cls, bp, extrapolate=None):
        """
        Construct a piecewise polynomial in the power basis
        from a polynomial in Bernstein basis.

        Parameters
        ----------
        bp : BPoly
            A Bernstein basis polynomial, as created by BPoly
        extrapolate : bool or 'periodic', optional
            If bool, determines whether to extrapolate to out-of-bounds points
            based on first and last intervals, or to return NaNs.
            If 'periodic', periodic extrapolation is used. Default is True.
        """
        dx = np.diff(bp.x)
        k = bp.c.shape[0] - 1  # polynomial order

        rest = (None,)*(bp.c.ndim-2)

        c = np.zeros_like(bp.c)
        for a in range(k+1):
            factor = (-1)**(a) * s.comb(k, a) * bp.c[a]
            for s in range(a, k+1):
                val = s.comb(k-a, s-a) * (-1)**s
                c[k-s] += factor * val / dx[(slice(None),)+rest]**s

        if extrapolate is None:
            extrapolate = bp.extrapolate

        return cls.construct_fast(c, bp.x, extrapolate, bp.axis)
//  [python]
def from_bernstein_basis(cls, bp, extrapolate=None):
        """
        Construct a piecewise polynomial in the power basis
        from a polynomial in Bernstein basis.

        Parameters
        ----------
        bp : BPoly
            A Bernstein basis polynomial, as created by BPoly
        extrapolate : bool or 'periodic', optional
            If bool, determines whether to extrapolate to out-of-bounds points
            based on first and last intervals, or to return NaNs.
            If 'periodic', periodic extrapolation is used. Default is True.
        """
        dx = np.diff(bp.x)
        k = bp.c.shape[0] - 1  # polynomial order

        rest = (None,)*(bp.c.ndim-2)

        c = np.zeros_like(bp.c)
        for a in range(k+1):
            factor = (-1)**(a) * comb(k, a) * bp.c[a]
            for s in range(a, k+1):
                val = comb(k-a, s-a) * (-1)**s
                c[k-s] += factor * val / dx[(slice(None),)+rest]**s

        if extrapolate is None:
            extrapolate = bp.extrapolate

        return cls.construct_fast(c, bp.x, extrapolate, bp.axis)
//  [python]
_r50 = np.arange(50)
comb = jnp.array(scipy.special.comb(_r50[:, None], _r50[None], exact=False))
//  [python]
_r50 = np.arange(50)
comb = jnp.array(scipy.special.comb(_r50[:, None], _r50[None]))
//  [python]
def uniformpoint(self, popsize):
        """
        构建参考点
        :param popsize:
        :return:
        """
        H1 = 1
        while (self.comb(H1 + self.M - 1, self.M - 1) <= popsize):
            H1 = H1 + 1
        H1 = H1 - 1
        Z = np.array(list(self.combinations(range(H1 + self.M - 1), self.M - 1))) - np.tile(
            np.array(list(range(self.M - 1))), (int(self.comb(H1 + self.M - 1, self.M - 1)), 1))
        Z = (np.hstack((Z, H1 + np.zeros((Z.shape[0], 1)))) - np.hstack((np.zeros((Z.shape[0], 1)), Z))) / H1
        if H1 < self.M:
            H2 = 0
            while (self.comb(H1 + self.M - 1, self.M - 1) + self.comb(H2 + self.M - 1, self.M - 1) <= popsize):
                H2 = H2 + 1
            H2 = H2 - 1
            if H2 > 0:
                W2 = np.array(list(self.combinations(range(H2 + self.M - 1), self.M - 1))) - np.tile(
                    np.array(list(range(self.M - 1))), (int(self.comb(H2 + self.M - 1, self.M - 1)), 1))
                W2 = (np.hstack((W2, H2 + np.zeros((W2.shape[0], 1)))) - np.hstack(
                    (np.zeros((W2.shape[0], 1)), W2))) / H2
                W2 = W2 / 2 + 1 / (2 * self.M)
                Z = np.vstack((Z, W2))  # 按列合并
        Z[Z < 1e-6] = 1e-6
        popsize = Z.shape[0]
        return Z, popsize
//  [python]
def uniformpoint(self, popsize):
        """
        构建参考点
        :param popsize:
        :return:
        """
        H1 = 1
        while (comb(H1 + self.M - 1, self.M - 1) <= popsize):
            H1 = H1 + 1
        H1 = H1 - 1
        Z = np.array(list(combinations(range(H1 + self.M - 1), self.M - 1))) - np.tile(
            np.array(list(range(self.M - 1))), (int(comb(H1 + self.M - 1, self.M - 1)), 1))
        Z = (np.hstack((Z, H1 + np.zeros((Z.shape[0], 1)))) - np.hstack((np.zeros((Z.shape[0], 1)), Z))) / H1
        if H1 < self.M:
            H2 = 0
            while (comb(H1 + self.M - 1, self.M - 1) + comb(H2 + self.M - 1, self.M - 1) <= popsize):
                H2 = H2 + 1
            H2 = H2 - 1
            if H2 > 0:
                W2 = np.array(list(combinations(range(H2 + self.M - 1), self.M - 1))) - np.tile(
                    np.array(list(range(self.M - 1))), (int(comb(H2 + self.M - 1, self.M - 1)), 1))
                W2 = (np.hstack((W2, H2 + np.zeros((W2.shape[0], 1)))) - np.hstack(
                    (np.zeros((W2.shape[0], 1)), W2))) / H2
                W2 = W2 / 2 + 1 / (2 * self.M)
                Z = np.vstack((Z, W2))  # 按列合并
        Z[Z < 1e-6] = 1e-6
        popsize = Z.shape[0]
        return Z, popsize
//  [python]
def bernstein_poly(n, i, t):
    """
    Bernstein polynom.
    :param n: (int) polynom degree
    :param i: (int)
    :param t: (float)
    :return: (float)
    """
    return s.comb(n, i) * t ** i * (1 - t) ** (n - i)
//  [python]
def bernstein_poly(n, i, t):
    """
    Bernstein polynom.
    :param n: (int) polynom degree
    :param i: (int)
    :param t: (float)
    :return: (float)
    """
    return scipy.special.comb(n, i) * t ** i * (1 - t) ** (n - i)
//  [python]
def smoothstep(x, NN=1, xmin=0., xmax=1.):
    N = math.ceil(NN)
    x = np.clip((x - xmin) / (xmax - xmin), 0, 1)
    result = 0
    for n in range(0, N+1):
         result += s.comb(N+n, n) * s.comb(2*N+1, N-n) * (-x)**n
    result *= x**(N+1)
    if NN != N: result = (x + result) / 2
    return result
//  [python]
def smoothstep(x, NN=1, xmin=0., xmax=1.):
    N = math.ceil(NN)
    x = np.clip((x - xmin) / (xmax - xmin), 0, 1)
    result = 0
    for n in range(0, N+1):
         result += scipy.special.comb(N+n, n) * scipy.special.comb(2*N+1, N-n) * (-x)**n
    result *= x**(N+1)
    if NN != N: result = (x + result) / 2
    return result
//  [python]
def ser2ber(q,n,d,t,ps):
    """
    Converts symbol error rate to bit error rate. Taken from Ziemer and
    Tranter page 650. Necessary when comparing different types of block codes.
    
    parameters
    ----------  
    q: size of the code alphabet for given modulation type (BPSK=2)
    n: number of channel bits
    d: distance (2e+1) where e is the number of correctable errors per code word.
       For hamming codes, e=1, so d=3.
    t: number of correctable errors per code word
    ps: symbol error probability vector
    
    returns
    -------
    ber: bit error rate
    
    """
    lnps = len(ps) # len of error vector
    ber = np.zeros(lnps) # inialize output vector
    for k in range(0,lnps): # iterate error vector
        ser = ps[k] # channel symbol error rate
        sum1 = 0 # initialize sums
        sum2 = 0
        for i in range(t+1,d+1):
            term = s.comb(n,i)*(ser**i)*((1-ser))**(n-i)
            sum1 = sum1 + term
        for i in range(d+1,n+1):
            term = (i)*s.comb(n,i)*(ser**i)*((1-ser)**(n-i))
            sum2 = sum2+term
        ber[k] = (q/(2*(q-1)))*((d/n)*sum1+(1/n)*sum2)
    
    return ber
//  [python]
def ser2ber(q,n,d,t,ps):
    """
    Converts symbol error rate to bit error rate. Taken from Ziemer and
    Tranter page 650. Necessary when comparing different types of block codes.
    
    parameters
    ----------  
    q: size of the code alphabet for given modulation type (BPSK=2)
    n: number of channel bits
    d: distance (2e+1) where e is the number of correctable errors per code word.
       For hamming codes, e=1, so d=3.
    t: number of correctable errors per code word
    ps: symbol error probability vector
    
    returns
    -------
    ber: bit error rate
    
    """
    lnps = len(ps) # len of error vector
    ber = np.zeros(lnps) # inialize output vector
    for k in range(0,lnps): # iterate error vector
        ser = ps[k] # channel symbol error rate
        sum1 = 0 # initialize sums
        sum2 = 0
        for i in range(t+1,d+1):
            term = special.comb(n,i)*(ser**i)*((1-ser))**(n-i)
            sum1 = sum1 + term
        for i in range(d+1,n+1):
            term = (i)*special.comb(n,i)*(ser**i)*((1-ser)**(n-i))
            sum2 = sum2+term
        ber[k] = (q/(2*(q-1)))*((d/n)*sum1+(1/n)*sum2)
    
    return ber
//  [python]
def excite_bulk(sd, occ_indices, vir_indices, excite_order):  # pylint: disable=W0621
    """Return all possible excitations from the given occupied and virtual orbitals.

    Parameters
    ----------
    sd : int
        Slater determinant to which the excitation operators is applied.
    occ_indices : np.ndarray
        Tuple of occupied orbital indices.
    vir_indices : np.ndarray
        Tuple of virtual orbital indices.
    excite_order : int
        Order of excitation.

    Returns
    -------
    excited_sds : np.ndarray(dtype=int)
        Integers that describe the occupations of a excitations as a bitstring.

    Raises
    ------
    ValueError
        If the length of indices is not even (cannot evenly split up the indices in two).

    """
    if __debug__:
        occ_indices = np.array(occ_indices)
        vir_indices = np.array(vir_indices)
        if not (isinstance(excite_order, (int, np.integer)) and excite_order >= 0):
            raise TypeError("Order of excitation must be an integer greater than or equal to zero.")

    # def fromiter(iterator, dtype, ydim, count):
    #     return np.fromiter(
    #         it.chain.from_iterable(iterator), dtype, count=int(count)
    #     ).reshape(-1, ydim)

    if excite_order == 0:
        return np.array([sd], dtype=int)

    occ_indices = np.fromiter(
        it.chain.from_iterable(it.combinations(occ_indices.tolist(), excite_order)),
        int,
        count=excite_order * int(s.comb(occ_indices.size, excite_order)),
    ).reshape(-1, excite_order)
    occ_indices = np.left_shift(1, occ_indices)
    if excite_order >= 2:
        occ_indices = np.bitwise_or.reduce(occ_indices.T)  # pylint: disable=E1101

    vir_indices = np.fromiter(
        it.chain.from_iterable(it.combinations(vir_indices.tolist(), excite_order)),
        int,
        count=excite_order * int(s.comb(vir_indices.size, excite_order)),
    ).reshape(-1, excite_order)
    vir_indices = np.left_shift(1, vir_indices)
    if excite_order >= 2:
        vir_indices = np.bitwise_or.reduce(vir_indices.T)  # pylint: disable=E1101

    return np.ravel(np.bitwise_or(np.bitwise_xor(sd, occ_indices)[:, None], vir_indices[None, :]))
//  [python]
def excite_bulk(sd, occ_indices, vir_indices, excite_order):  # pylint: disable=W0621
    """Return all possible excitations from the given occupied and virtual orbitals.

    Parameters
    ----------
    sd : int
        Slater determinant to which the excitation operators is applied.
    occ_indices : np.ndarray
        Tuple of occupied orbital indices.
    vir_indices : np.ndarray
        Tuple of virtual orbital indices.
    excite_order : int
        Order of excitation.

    Returns
    -------
    excited_sds : np.ndarray(dtype=int)
        Integers that describe the occupations of a excitations as a bitstring.

    Raises
    ------
    ValueError
        If the length of indices is not even (cannot evenly split up the indices in two).

    """
    if __debug__:
        occ_indices = np.array(occ_indices)
        vir_indices = np.array(vir_indices)
        if not (isinstance(excite_order, (int, np.integer)) and excite_order >= 0):
            raise TypeError("Order of excitation must be an integer greater than or equal to zero.")

    # def fromiter(iterator, dtype, ydim, count):
    #     return np.fromiter(
    #         it.chain.from_iterable(iterator), dtype, count=int(count)
    #     ).reshape(-1, ydim)

    if excite_order == 0:
        return np.array([sd], dtype=int)

    occ_indices = np.fromiter(
        it.chain.from_iterable(it.combinations(occ_indices.tolist(), excite_order)),
        int,
        count=excite_order * int(scipy.special.comb(occ_indices.size, excite_order)),
    ).reshape(-1, excite_order)
    occ_indices = np.left_shift(1, occ_indices)
    if excite_order >= 2:
        occ_indices = np.bitwise_or.reduce(occ_indices.T)  # pylint: disable=E1101

    vir_indices = np.fromiter(
        it.chain.from_iterable(it.combinations(vir_indices.tolist(), excite_order)),
        int,
        count=excite_order * int(scipy.special.comb(vir_indices.size, excite_order)),
    ).reshape(-1, excite_order)
    vir_indices = np.left_shift(1, vir_indices)
    if excite_order >= 2:
        vir_indices = np.bitwise_or.reduce(vir_indices.T)  # pylint: disable=E1101

    return np.ravel(np.bitwise_or(np.bitwise_xor(sd, occ_indices)[:, None], vir_indices[None, :]))
//  [python]
def make_hamiltonian(edges, number_of_spins=None):
    """
    Returns the Heisenberg Hamiltonian on the lattice defined by the adjacency
    list edges.
    """
    n = (
        number_of_spins
        if number_of_spins is not None
        else deduce_number_of_spins(edges)
    )
    edges = np.array(edges, dtype=np.int64).reshape(-1, 2)
    # List of all spins within a sector with a certain magnetisation
    magnetisation = n % 2
    number_ups = (n + magnetisation) // 2
    shift = number_ups * (number_ups - 1) // 2 if number_ups > 0 else 0
    print(sector(n, magnetisation))
    all_spins = np.fromiter(
        sector(n, magnetisation),
        dtype=np.uint64,
        count=int(s(n, number_ups)),
    )
    print(all_spins, all_spins.shape)
    # if 2 ** n > 134217728:
    #     g_to_l = dict(((s, i) for i, s in enumerate(all_spins)))
    # else:
    #     g_to_l = np.empty(2**n, dtype=np.int64)
    #     g_to_l[:] = 2**63 - 1
    #     for i, s in enumerate(all_spins):
    #         g_to_l[s] = i
    global_to_local = np.empty((len(all_spins), 2), dtype=np.uint64)
    for i, s in enumerate(all_spins):
        global_to_local[i, 0] = s
        global_to_local[i, 1] = i

    size_step = 65536000
    size = min(size_step, len(all_spins) * (len(edges) + 1))
    data = np.empty(size, dtype=np.float64)
    row_ind = np.empty(size, dtype=np.int64)
    col_ind = np.empty(size, dtype=np.int64)
    coeffs = np.empty(len(edges) + 1, dtype=np.float64)
    indices = np.empty(len(edges) + 1, dtype=np.int64)
    count = 0
    for s in all_spins:
        k = _fill_row(s, n, edges, coeffs, indices)
        if count + k > size:
            size += size_step
            data = np.resize(data, size)
            row_ind = np.resize(row_ind, size)
            col_ind = np.resize(col_ind, size)
        data[count : count + k] = coeffs[:k]
        row_ind[count : count + k] = _binary_search(global_to_local, s)
        col_ind[count : count + k] = np.fromiter(
            (_binary_search(global_to_local, i) for i in indices[:k]),
            dtype=np.int64,
            count=k,
        )
        # row_ind[count:count + k] = g_to_l[s]
        # col_ind[count:count + k] = np.fromiter((g_to_l[i] for i in indices[:k]), dtype=np.int64, count=k)
        count += k
    data = data[:count]
    row_ind = row_ind[:count]
    col_ind = col_ind[:count]
    matrix = scipy.sparse.csr_matrix(
        (data, (row_ind, col_ind)), shape=(len(all_spins), len(all_spins))
    )
    return Hamiltonian(n, matrix, all_spins)
//  [python]
def make_hamiltonian(edges, number_of_spins=None):
    """
    Returns the Heisenberg Hamiltonian on the lattice defined by the adjacency
    list edges.
    """
    n = (
        number_of_spins
        if number_of_spins is not None
        else deduce_number_of_spins(edges)
    )
    edges = np.array(edges, dtype=np.int64).reshape(-1, 2)
    # List of all spins within a sector with a certain magnetisation
    magnetisation = n % 2
    number_ups = (n + magnetisation) // 2
    shift = number_ups * (number_ups - 1) // 2 if number_ups > 0 else 0
    print(sector(n, magnetisation))
    all_spins = np.fromiter(
        sector(n, magnetisation),
        dtype=np.uint64,
        count=int(scipy.special.comb(n, number_ups)),
    )
    print(all_spins, all_spins.shape)
    # if 2 ** n > 134217728:
    #     g_to_l = dict(((s, i) for i, s in enumerate(all_spins)))
    # else:
    #     g_to_l = np.empty(2**n, dtype=np.int64)
    #     g_to_l[:] = 2**63 - 1
    #     for i, s in enumerate(all_spins):
    #         g_to_l[s] = i
    global_to_local = np.empty((len(all_spins), 2), dtype=np.uint64)
    for i, s in enumerate(all_spins):
        global_to_local[i, 0] = s
        global_to_local[i, 1] = i

    size_step = 65536000
    size = min(size_step, len(all_spins) * (len(edges) + 1))
    data = np.empty(size, dtype=np.float64)
    row_ind = np.empty(size, dtype=np.int64)
    col_ind = np.empty(size, dtype=np.int64)
    coeffs = np.empty(len(edges) + 1, dtype=np.float64)
    indices = np.empty(len(edges) + 1, dtype=np.int64)
    count = 0
    for s in all_spins:
        k = _fill_row(s, n, edges, coeffs, indices)
        if count + k > size:
            size += size_step
            data = np.resize(data, size)
            row_ind = np.resize(row_ind, size)
            col_ind = np.resize(col_ind, size)
        data[count : count + k] = coeffs[:k]
        row_ind[count : count + k] = _binary_search(global_to_local, s)
        col_ind[count : count + k] = np.fromiter(
            (_binary_search(global_to_local, i) for i in indices[:k]),
            dtype=np.int64,
            count=k,
        )
        # row_ind[count:count + k] = g_to_l[s]
        # col_ind[count:count + k] = np.fromiter((g_to_l[i] for i in indices[:k]), dtype=np.int64, count=k)
        count += k
    data = data[:count]
    row_ind = row_ind[:count]
    col_ind = col_ind[:count]
    matrix = scipy.sparse.csr_matrix(
        (data, (row_ind, col_ind)), shape=(len(all_spins), len(all_spins))
    )
    return Hamiltonian(n, matrix, all_spins)
//  [python]
def get_IEI(title, show_img=False, save_img_pth=None,exclude_last_n_month=1,normalized=False):
    spms = get_s2citaions_per_month(title, 2000)
    actual_len = 6 if len(spms) >= 6+exclude_last_n_month else len(spms) -exclude_last_n_month
    # print(f'acutal len:{actual_len}')
    if actual_len < 6:
        rst = {}
        rst['L6'] = float('-inf')
        rst['I6'] = float('-inf')
        return rst
    # 六个坐标点
    x = [i for i in range(actual_len)]
    subset = list(spms.items())[exclude_last_n_month:exclude_last_n_month+actual_len][::-1]
    y = [item[1] for item in subset]
    if normalized:
        y = [(y_i - min(y)) / (max(y) - min(y)) for y_i in y]
    # 拟合五次贝塞尔曲线
    t = np.linspace(0, 1, 100)
    n = len(x) - 1  # 控制点的数量
    curve_x = np.zeros_like(t)
    curve_y = np.zeros_like(t)
    # print(n,y)

    for i in range(n + 1):
        curve_x += s.comb(n, i) * (1 - t) ** (n - i) * t ** i * x[i]
        curve_y += s.comb(n, i) * (1 - t) ** (n - i) * t ** i * y[i]
    if show_img or save_img_pth:
        # 绘制曲线
        plt.clf()
        fig = plt.figure(figsize=(6, 4), dpi=300)  # Increase DPI for high resolution
        plt.style.use('seaborn-v0_8')
        plt.plot(x, y, 'o', color='darkorange', label='Data Point')  # darkorange for contrast
        plt.plot(curve_x, curve_y, color='steelblue', label='Bezier Curve')  # steelblue for the line

        plt.legend()
        plt.xlabel('Month')
        plt.ylabel('Received Citation')
        # plt.title('Quintic Bezier Curve')
        plt.grid(True)
        if save_img_pth:
            plt.savefig(save_img_pth,dpi=300, bbox_inches='tight')
        if show_img:
            plt.show()

    dx_dt = np.zeros_like(t)
    dy_dt = np.zeros_like(t)
    # print(y)
    for i in range(n):
        dx_dt += s.comb(n - 1, i) * (1 - t) ** (n - i - 1) * t ** i * (x[i + 1] - x[i])
        dy_dt += s.comb(n - 1, i) * (1 - t) ** (n - i - 1) * t ** i * (y[i + 1] - y[i])

    I6 = dy_dt[-1] / dx_dt[-1]
    # print(len(dy_dt))
    slope_avg = []
    # sum([dy_dt[i-1] / dx_dt[i-1] for i in range(0, 101, 20)])/n+1
    for i in range(0, 100, 20):
        # print((curve_x[i-1],curve_y[i-1]))
        slope_avg.append(dy_dt[i] / dx_dt[i])
    slope_avg.append(I6)
    print(slope_avg)
    print('平均', sum(slope_avg) / 6)
    print("瞬时斜率:", I6)
    rst = {}
    rst['L6'] = sum(slope_avg) / 6 if not math.isnan(sum(slope_avg)) else float('-inf')
    rst['I6'] = I6 if not math.isnan(I6) else float('-inf')
    return rst
//  [python]
def get_IEI(title, show_img=False, save_img_pth=None,exclude_last_n_month=1,normalized=False):
    spms = get_s2citaions_per_month(title, 2000)
    actual_len = 6 if len(spms) >= 6+exclude_last_n_month else len(spms) -exclude_last_n_month
    # print(f'acutal len:{actual_len}')
    if actual_len < 6:
        rst = {}
        rst['L6'] = float('-inf')
        rst['I6'] = float('-inf')
        return rst
    # 六个坐标点
    x = [i for i in range(actual_len)]
    subset = list(spms.items())[exclude_last_n_month:exclude_last_n_month+actual_len][::-1]
    y = [item[1] for item in subset]
    if normalized:
        y = [(y_i - min(y)) / (max(y) - min(y)) for y_i in y]
    # 拟合五次贝塞尔曲线
    t = np.linspace(0, 1, 100)
    n = len(x) - 1  # 控制点的数量
    curve_x = np.zeros_like(t)
    curve_y = np.zeros_like(t)
    # print(n,y)

    for i in range(n + 1):
        curve_x += comb(n, i) * (1 - t) ** (n - i) * t ** i * x[i]
        curve_y += comb(n, i) * (1 - t) ** (n - i) * t ** i * y[i]
    if show_img or save_img_pth:
        # 绘制曲线
        plt.clf()
        fig = plt.figure(figsize=(6, 4), dpi=300)  # Increase DPI for high resolution
        plt.style.use('seaborn-v0_8')
        plt.plot(x, y, 'o', color='darkorange', label='Data Point')  # darkorange for contrast
        plt.plot(curve_x, curve_y, color='steelblue', label='Bezier Curve')  # steelblue for the line

        plt.legend()
        plt.xlabel('Month')
        plt.ylabel('Received Citation')
        # plt.title('Quintic Bezier Curve')
        plt.grid(True)
        if save_img_pth:
            plt.savefig(save_img_pth,dpi=300, bbox_inches='tight')
        if show_img:
            plt.show()

    dx_dt = np.zeros_like(t)
    dy_dt = np.zeros_like(t)
    # print(y)
    for i in range(n):
        dx_dt += comb(n - 1, i) * (1 - t) ** (n - i - 1) * t ** i * (x[i + 1] - x[i])
        dy_dt += comb(n - 1, i) * (1 - t) ** (n - i - 1) * t ** i * (y[i + 1] - y[i])

    I6 = dy_dt[-1] / dx_dt[-1]
    # print(len(dy_dt))
    slope_avg = []
    # sum([dy_dt[i-1] / dx_dt[i-1] for i in range(0, 101, 20)])/n+1
    for i in range(0, 100, 20):
        # print((curve_x[i-1],curve_y[i-1]))
        slope_avg.append(dy_dt[i] / dx_dt[i])
    slope_avg.append(I6)
    print(slope_avg)
    print('平均', sum(slope_avg) / 6)
    print("瞬时斜率:", I6)
    rst = {}
    rst['L6'] = sum(slope_avg) / 6 if not math.isnan(sum(slope_avg)) else float('-inf')
    rst['I6'] = I6 if not math.isnan(I6) else float('-inf')
    return rst
//  [python]
def __init__(self, nb_states, obs_dim, act_dim, prior, degree=1):

        self.nb_states = nb_states
        self.obs_dim = obs_dim
        self.act_dim = act_dim

        self.degree = degree

        self.feat_dim = int(s.comb(self.degree + self.obs_dim, self.degree)) - 1
        self.basis = PolynomialFeatures(self.degree, include_bias=False)

        self.input_dim = self.feat_dim + 1
        self.output_dim = self.act_dim

        likelihood_precision_prior = prior['likelihood_precision_prior']
        parameter_precision_prior = prior['parameter_precision_prior']

        super().__init__(self.nb_states,
                         self.input_dim,
                         self.output_dim,
                         likelihood_precision_prior,
                         parameter_precision_prior)
//  [python]
def __init__(self, nb_states, obs_dim, act_dim, prior, degree=1):

        self.nb_states = nb_states
        self.obs_dim = obs_dim
        self.act_dim = act_dim

        self.degree = degree

        self.feat_dim = int(comb(self.degree + self.obs_dim, self.degree)) - 1
        self.basis = PolynomialFeatures(self.degree, include_bias=False)

        self.input_dim = self.feat_dim + 1
        self.output_dim = self.act_dim

        likelihood_precision_prior = prior['likelihood_precision_prior']
        parameter_precision_prior = prior['parameter_precision_prior']

        super().__init__(self.nb_states,
                         self.input_dim,
                         self.output_dim,
                         likelihood_precision_prior,
                         parameter_precision_prior)
//  [python]
def __init__(self, nb_states, obs_dim, act_dim,
                 prior, degree=1, likelihood=None):

        self.nb_states = nb_states
        self.obs_dim = obs_dim
        self.act_dim = act_dim

        self.degree = degree

        self.feat_dim = int(s.comb(self.degree + self.obs_dim, self.degree)) - 1
        self.basis = PolynomialFeatures(self.degree, include_bias=False)

        self.input_dim = self.feat_dim + 1
        self.output_dim = self.act_dim

        self.prior = prior
        self.posterior = copy.deepcopy(prior)

        # Linear-Gaussian likelihood
        if likelihood is not None:
            self.likelihood = likelihood
        else:
            As, lmbdas = self.prior.rvs()
            self.likelihood = StackedLinearGaussiansWithPrecision(size=self.nb_states,
                                                                  column_dim=self.input_dim,
                                                                  row_dim=self.output_dim,
                                                                  As=As, lmbdas=lmbdas, affine=True)
//  [python]
def __init__(self, nb_states, obs_dim, act_dim,
                 prior, degree=1, likelihood=None):

        self.nb_states = nb_states
        self.obs_dim = obs_dim
        self.act_dim = act_dim

        self.degree = degree

        self.feat_dim = int(sc.special.comb(self.degree + self.obs_dim, self.degree)) - 1
        self.basis = PolynomialFeatures(self.degree, include_bias=False)

        self.input_dim = self.feat_dim + 1
        self.output_dim = self.act_dim

        self.prior = prior
        self.posterior = copy.deepcopy(prior)

        # Linear-Gaussian likelihood
        if likelihood is not None:
            self.likelihood = likelihood
        else:
            As, lmbdas = self.prior.rvs()
            self.likelihood = StackedLinearGaussiansWithPrecision(size=self.nb_states,
                                                                  column_dim=self.input_dim,
                                                                  row_dim=self.output_dim,
                                                                  As=As, lmbdas=lmbdas, affine=True)
//  [python]
def __init__(self, nb_states, obs_dim, act_dim,
                 degree=1, **kwargs):

        self.nb_states = nb_states
        self.obs_dim = obs_dim
        self.act_dim = act_dim

        self.degree = degree
        self.feat_dim = int(s.comb(self.degree + self.obs_dim, self.degree)) - 1
        self.basis = PolynomialFeatures(self.degree, include_bias=False)

        # self.K = npr.randn(self.nb_states, self.act_dim, self.feat_dim)
        # self.kff = npr.randn(self.nb_states, self.act_dim)
        # self._sigma_chol = 5. * npr.randn(self.nb_states, self.act_dim, self.act_dim)

        self.K = np.zeros((self.nb_states, self.act_dim, self.feat_dim))
        self.kff = np.zeros((self.nb_states, self.act_dim))
        self._sigma_chol = np.zeros((self.nb_states, self.act_dim, self.act_dim))

        for k in range(self.nb_states):
            _sigma = invwishart.rvs(self.act_dim + 1, np.eye(self.act_dim))
            self._sigma_chol[k] = np.linalg.cholesky(_sigma * np.eye(self.act_dim))
            self.K[k] = mvn.rvs(mean=None, cov=1e2 * _sigma, size=(self.feat_dim, )).T
            self.kff[k] = mvn.rvs(mean=None, cov=1e2 * _sigma, size=(1, ))