jiahuimbzuai/CoQuIR huggingface dataset:
//  [python]
def __init__(self, annotators, documents, labels, eval_func=exact_match_instance_evaluation, token_func=None):
        assert len(annotators) > 1, 'At least two annotators are necessary to compute agreement!'
        num_pairs = comb(len(annotators), 2, exact=True)
        # (p, d, c, l) where p := annotator pairs, d := documents, c := counts (tp, fp, fn), l := labels
        self._pdcl = np.zeros((num_pairs, len(documents), 3, len(labels)))
        self._documents = list(documents)
        self._doc2idx = {d: i for i, d in enumerate(documents)}
        self._labels = list(labels)
        self._label2idx = {l: i for i, l in enumerate(labels)}
        self._annotators = list(annotators)
        self._pairs = [pair for pair in combinations(annotators, 2)]
        self._pair2idx = {p: i for i, p in enumerate(self._pairs)}
        # add pairs in reverse order (same index)
        for (a1, a2), value in self._pair2idx.copy().items():
            self._pair2idx[(a2, a1)] = value
        self._eval_func = eval_func  # function used to extract true positives, false positives and false negatives
        self._token_func = token_func  # function used for tokenization
        self._compute_tp_fp_fn(documents)
//  [python]
def EWS_select_BH():
    """
    Plot the fraction of long duration EWS events
    that will be due to black holes.
    """

    def binom(n,k,p):
        """
        n = total
        k = success
        p = prob of success
        """
        prob = s.comb(n,k) * p**k * (1-p)**(n-k)
        err = np.sqrt(n*p*(1-p))
        
        return prob, err

    def calc_frac(n_bh, n_not_bh):
        """
        Calculate the fraction of long duration events
        that have black hole lenses
        """        
        frac = n_bh/(n_not_bh + n_bh)
        
        bh_err = np.sqrt(n_bh)
        not_bh_err = np.sqrt(n_not_bh)
        n_bh = np.array(n_bh)
        n_not_bh = np.array(n_not_bh)
        term1 = bh_err * n_not_bh
        term2 = not_bh_err * n_bh
        term3 = (n_bh + n_not_bh)**2
        frac_err = np.sqrt(term1**2 + term2**2)/term3

        return frac, frac_err

    # For popsycle
    def calc_fraction(t, mintE):
        """
        Calculate the fraction of long duration events
        that have black hole lenses
        """

        not_bh_idx = np.where((t['t_E'] > mintE) & 
                              (t['rem_id_L'] != 103))[0]
        
        bh_idx = np.where((t['t_E'] > mintE) & 
                          (t['rem_id_L'] == 103))[0]
        
        frac = len(bh_idx)/(len(not_bh_idx) + len(bh_idx))
        
        bh_err = np.sqrt(len(bh_idx))
        not_bh_err = np.sqrt(len(not_bh_idx))
        n_bh = np.array(len(bh_idx))
        n_not_bh = np.array(len(not_bh_idx))
        term1 = bh_err * n_not_bh
        term2 = not_bh_err * n_bh
        term3 = (n_bh + n_not_bh)**2
        frac_err = np.sqrt(term1**2 + term2**2)/term3

        return frac, frac_err

    print(calc_frac(1, 9))
    print(calc_frac(2, 8))

    t = Table.read('/u/casey/scratch/papers/microlens_2019/popsycle_rr_files/Mock_EWS_v2.fits')

#    times = np.linspace(60, 150, 20)
    times = np.linspace(60, 200, 20)

    frac_arr = np.zeros(len(times))
    frac_err_arr = np.zeros(len(times))

    for i in np.arange(len(times)):
        frac_arr[i], frac_err_arr[i] = calc_fraction(t, mintE = times[i])

    prob1, err1 = binom(10, 1, 0.4)
    print(prob1, err1)

    fig = plt.figure(11, figsize=(4,4))
    plt.subplots_adjust(bottom=0.2, top=0.97, left=0.25, right=0.95)
    plt.clf()
    plt.fill_between(times, frac_arr-frac_err_arr, frac_arr+frac_err_arr, alpha=0.5, color='tab:blue', label='Expectation')
#    plt.errorbar(120, 1/10, yerr=0.09486832980505139, marker= 's', capsize=5, elinewidth = 2, ms = 10, ls = 'None', label='Sample', color='k')
    plt.errorbar(120, calc_frac(2, 8)[0], yerr=calc_frac(2, 8)[1], marker= 's', capsize=5, elinewidth = 2, ms = 10, ls = 'None', label='Sample', color='k')
    plt.ylabel('Fraction of BH events')
    plt.xlabel('Minimum $t_E$ (days)')
    plt.xlim(60, 200)
    plt.ylim(0, 0.7)
    plt.legend(loc=2)
    plt.show()
    plt.savefig('expect_vs_detect.png')

    return
//  [python]
def EWS_select_BH():
    """
    Plot the fraction of long duration EWS events
    that will be due to black holes.
    """

    def binom(n,k,p):
        """
        n = total
        k = success
        p = prob of success
        """
        prob = scipy.special.comb(n,k) * p**k * (1-p)**(n-k)
        err = np.sqrt(n*p*(1-p))
        
        return prob, err

    def calc_frac(n_bh, n_not_bh):
        """
        Calculate the fraction of long duration events
        that have black hole lenses
        """        
        frac = n_bh/(n_not_bh + n_bh)
        
        bh_err = np.sqrt(n_bh)
        not_bh_err = np.sqrt(n_not_bh)
        n_bh = np.array(n_bh)
        n_not_bh = np.array(n_not_bh)
        term1 = bh_err * n_not_bh
        term2 = not_bh_err * n_bh
        term3 = (n_bh + n_not_bh)**2
        frac_err = np.sqrt(term1**2 + term2**2)/term3

        return frac, frac_err

    # For popsycle
    def calc_fraction(t, mintE):
        """
        Calculate the fraction of long duration events
        that have black hole lenses
        """

        not_bh_idx = np.where((t['t_E'] > mintE) & 
                              (t['rem_id_L'] != 103))[0]
        
        bh_idx = np.where((t['t_E'] > mintE) & 
                          (t['rem_id_L'] == 103))[0]
        
        frac = len(bh_idx)/(len(not_bh_idx) + len(bh_idx))
        
        bh_err = np.sqrt(len(bh_idx))
        not_bh_err = np.sqrt(len(not_bh_idx))
        n_bh = np.array(len(bh_idx))
        n_not_bh = np.array(len(not_bh_idx))
        term1 = bh_err * n_not_bh
        term2 = not_bh_err * n_bh
        term3 = (n_bh + n_not_bh)**2
        frac_err = np.sqrt(term1**2 + term2**2)/term3

        return frac, frac_err

    print(calc_frac(1, 9))
    print(calc_frac(2, 8))

    t = Table.read('/u/casey/scratch/papers/microlens_2019/popsycle_rr_files/Mock_EWS_v2.fits')

#    times = np.linspace(60, 150, 20)
    times = np.linspace(60, 200, 20)

    frac_arr = np.zeros(len(times))
    frac_err_arr = np.zeros(len(times))

    for i in np.arange(len(times)):
        frac_arr[i], frac_err_arr[i] = calc_fraction(t, mintE = times[i])

    prob1, err1 = binom(10, 1, 0.4)
    print(prob1, err1)

    fig = plt.figure(11, figsize=(4,4))
    plt.subplots_adjust(bottom=0.2, top=0.97, left=0.25, right=0.95)
    plt.clf()
    plt.fill_between(times, frac_arr-frac_err_arr, frac_arr+frac_err_arr, alpha=0.5, color='tab:blue', label='Expectation')
#    plt.errorbar(120, 1/10, yerr=0.09486832980505139, marker= 's', capsize=5, elinewidth = 2, ms = 10, ls = 'None', label='Sample', color='k')
    plt.errorbar(120, calc_frac(2, 8)[0], yerr=calc_frac(2, 8)[1], marker= 's', capsize=5, elinewidth = 2, ms = 10, ls = 'None', label='Sample', color='k')
    plt.ylabel('Fraction of BH events')
    plt.xlabel('Minimum $t_E$ (days)')
    plt.xlim(60, 200)
    plt.ylim(0, 0.7)
    plt.legend(loc=2)
    plt.show()
    plt.savefig('expect_vs_detect.png')

    return
//  [python]
def qcbc_hamming_bound(N, D, q=4):
    # N = length of codeword
    # D is min ham
    # q is alphabet size    

    t = (D - 1) // 2
    denominator = sum(s.comb(N, i) * (q - 1)**i for i in range(t + 1))
    if denominator == 0:
        return 0  # Avoid division by zero
    return q**N / denominator
//  [python]
def qcbc_hamming_bound(N, D, q=4):
    # N = length of codeword
    # D is min ham
    # q is alphabet size    

    t = (D - 1) // 2
    denominator = sum(scipy.special.comb(N, i) * (q - 1)**i for i in range(t + 1))
    if denominator == 0:
        return 0  # Avoid division by zero
    return q**N / denominator
//  [python]
def _lex_index(n, k, lst):
    """Return  the lex index of a combination..

    Args:
        n (int): the total number of options .
        k (int): The number of elements.
        lst (list): list

    Returns:
        int: returns int index for lex order

    Raises:
        KaleidoscopeError: if length of list is not equal to k
    """
    if len(lst) != k:
        raise KaleidoscopeError("list should have length k")
    comb = list(map(lambda x: n - 1 - x, lst))
    dualm = sum([s.comb(comb[k - 1 - i], i + 1) for i in range(k)])
    return int(dualm)
//  [python]
def _lex_index(n, k, lst):
    """Return  the lex index of a combination..

    Args:
        n (int): the total number of options .
        k (int): The number of elements.
        lst (list): list

    Returns:
        int: returns int index for lex order

    Raises:
        KaleidoscopeError: if length of list is not equal to k
    """
    if len(lst) != k:
        raise KaleidoscopeError("list should have length k")
    comb = list(map(lambda x: n - 1 - x, lst))
    dualm = sum([spsp.comb(comb[k - 1 - i], i + 1) for i in range(k)])
    return int(dualm)
//  [python]
def dichotomies(d):
    total = s.comb(2**d, 2**(d - 1))
    aligned = sum(s.comb(2**d - 1, k) for k in range(0, d))
    return total, aligned
//  [python]
def dichotomies(d):
    total = sps.comb(2**d, 2**(d - 1))
    aligned = sum(sps.comb(2**d - 1, k) for k in range(0, d))
    return total, aligned
//  [python]
def evaluate_metric2(pred_l, gt_l):
    """
    Generate metric, number of mismatched pairs, normalized
    gt_l: ground truth array of ints. not their ordering!
    pred_l: is prediction of their ordering.
    """
    total_mis = 0
    vals, pred_order = torch.topk(pred_l, k=pred_l.size(-1), dim=-1, largest=False)  # all_data.clone()
    for i, pred_seq in enumerate(pred_l):
        mis_pair = 0
        for j, cur_num in enumerate(pred_seq[:-1]):
            #
            if args.no_repeat:
                mis_pair += (pred_seq[j + 1 :] <= cur_num).sum()
            else:
                mis_pair += (pred_seq[j:] < cur_num).sum()
        cor_pair = s.comb(len(pred_seq), 2) - mis_pair
        total_mis += cor_pair
    return total_mis.cpu().item() / len(pred_l)
//  [python]
def evaluate_metric2(pred_l, gt_l):
    """
    Generate metric, number of mismatched pairs, normalized
    gt_l: ground truth array of ints. not their ordering!
    pred_l: is prediction of their ordering.
    """
    total_mis = 0
    vals, pred_order = torch.topk(pred_l, k=pred_l.size(-1), dim=-1, largest=False)  # all_data.clone()
    for i, pred_seq in enumerate(pred_l):
        mis_pair = 0
        for j, cur_num in enumerate(pred_seq[:-1]):
            #
            if args.no_repeat:
                mis_pair += (pred_seq[j + 1 :] <= cur_num).sum()
            else:
                mis_pair += (pred_seq[j:] < cur_num).sum()
        cor_pair = scipy.special.comb(len(pred_seq), 2) - mis_pair
        total_mis += cor_pair
    return total_mis.cpu().item() / len(pred_l)
//  [python]
def test_4():
    n = 4
    n_params = scipy.misc.comb(n + 1, 2, exact=True)
    alpha = np.ones(n)
    beta = (np.arange(n_params - n) + 1).astype(float)
    counts = np.array([
        [10, 2, 0, 0],
        [1, 8, 2, 0],
        [0, 4, 10, 1],
        [0, 0, 2, 8]
    ]).astype(float)

    def log_posterior(theta):
        return _log_posterior(theta, counts, alpha, beta, n)

    # theta = np.random.randn(n_params)
    # log_posterior(theta)
    n_trials = 100
    random = np.random.RandomState(0)
    x0 = random.rand(n_trials, n_params)
    for i in range(n_trials):
        value = scipy.optimize.check_grad(
            lambda x: log_posterior(x)[0],
            lambda x: log_posterior(x)[1],
            x0[i])
        assert value < 1e-4
//  [python]
def test_4():
    n = 4
    # Importing comb from scipy.misc is deprecated in scipy 1.0.0.
    try:
        n_params = scipy.special.comb(n + 1, 2, exact=True)
    except ImportError:
        n_params = scipy.misc.comb(n + 1, 2, exact=True)
    alpha = np.ones(n)
    beta = (np.arange(n_params - n) + 1).astype(float)
    counts = np.array([
        [10, 2, 0, 0],
        [1, 8, 2, 0],
        [0, 4, 10, 1],
        [0, 0, 2, 8]
    ]).astype(float)

    def log_posterior(theta):
        return _log_posterior(theta, counts, alpha, beta, n)

    # theta = np.random.randn(n_params)
    # log_posterior(theta)
    n_trials = 100
    random = np.random.RandomState(0)
    x0 = random.rand(n_trials, n_params)
    for i in range(n_trials):
        value = scipy.optimize.check_grad(
            lambda x: log_posterior(x)[0],
            lambda x: log_posterior(x)[1],
            x0[i])
        assert value < 1e-4
//  [python]
def hypergraph_sbm_two_cluster(filename, n, r, p, q):
    """
    Generate a hypergraph from the hypergraph SBM and save the edgelist to the file specified.

    Generates a hypergraph with two clusters of size n. Every possible rank r edge inside each cluster is added with
    probability p. Every possible rank r edge between the two clusters is added with probability q.

    :param filename:
    :param n:
    :param r:
    :param p:
    :param q:
    :return:
    """
    hyplogging.logger.info(f"Generating two cluster SBM hypergraph.")
    hyplogging.logger.info(f"  filename = {filename}")
    hyplogging.logger.info(f"         n = {n}")
    hyplogging.logger.info(f"         r = {r}")
    hyplogging.logger.info(f"         p = {p}")
    hyplogging.logger.info(f"         q = {q}")

    with open(filename, 'w') as edgelist_out:
        # Start by generating the edges inside each cluster.
        # Work out how many of them there will be - this is a number drawn from the binomial distribution
        possible_edges_in_each_cluster = s.comb(n, r)
        num_edges_in_left_cluster = np.random.binomial(possible_edges_in_each_cluster, p)
        num_edges_in_right_cluster = np.random.binomial(possible_edges_in_each_cluster, p)
        hyplogging.logger.debug(f"Possible edges in each cluster: {possible_edges_in_each_cluster}")
        hyplogging.logger.debug(f"Edges in left cluster: {num_edges_in_left_cluster}")
        hyplogging.logger.debug(f"Edges in right cluster: {num_edges_in_right_cluster}")

        # Generate these edges
        for _ in range(num_edges_in_left_cluster):
            edge = random.sample(range(n), r)
            edgelist_out.write(' '.join(map(str, edge)))
            edgelist_out.write('\n')
        for _ in range(num_edges_in_right_cluster):
            edge = [v + n for v in random.sample(range(n), r)]
            edgelist_out.write(' '.join(map(str, edge)))
            edgelist_out.write('\n')

        # Now, generate the edges between the clusters.
        # We will consider each possible split between left and right clusters individually
        for r_prime in range(1, r):
            hyplogging.logger.debug(f"Considering r_prime = {r_prime}.")

            # Get the number of possible edges with this split.
            possible_edges_between_clusters = s.comb(n, r_prime) * s.comb(n, r - r_prime)
            num_edges_between_clusters = np.random.binomial(possible_edges_between_clusters, q)
            hyplogging.logger.debug(f"Possible edges between clusters: {possible_edges_between_clusters}")
            hyplogging.logger.debug(f"Edges between clusters: {num_edges_between_clusters}")

            # Generate the edges
            for _ in range(num_edges_between_clusters):
                edge = random.sample(range(n), r_prime) + [v + n for v in random.sample(range(n), r - r_prime)]
                edgelist_out.write(' '.join(map(str, edge)))
                edgelist_out.write('\n')
//  [python]
def hypergraph_sbm_two_cluster(filename, n, r, p, q):
    """
    Generate a hypergraph from the hypergraph SBM and save the edgelist to the file specified.

    Generates a hypergraph with two clusters of size n. Every possible rank r edge inside each cluster is added with
    probability p. Every possible rank r edge between the two clusters is added with probability q.

    :param filename:
    :param n:
    :param r:
    :param p:
    :param q:
    :return:
    """
    hyplogging.logger.info(f"Generating two cluster SBM hypergraph.")
    hyplogging.logger.info(f"  filename = {filename}")
    hyplogging.logger.info(f"         n = {n}")
    hyplogging.logger.info(f"         r = {r}")
    hyplogging.logger.info(f"         p = {p}")
    hyplogging.logger.info(f"         q = {q}")

    with open(filename, 'w') as edgelist_out:
        # Start by generating the edges inside each cluster.
        # Work out how many of them there will be - this is a number drawn from the binomial distribution
        possible_edges_in_each_cluster = scipy.special.comb(n, r)
        num_edges_in_left_cluster = np.random.binomial(possible_edges_in_each_cluster, p)
        num_edges_in_right_cluster = np.random.binomial(possible_edges_in_each_cluster, p)
        hyplogging.logger.debug(f"Possible edges in each cluster: {possible_edges_in_each_cluster}")
        hyplogging.logger.debug(f"Edges in left cluster: {num_edges_in_left_cluster}")
        hyplogging.logger.debug(f"Edges in right cluster: {num_edges_in_right_cluster}")

        # Generate these edges
        for _ in range(num_edges_in_left_cluster):
            edge = random.sample(range(n), r)
            edgelist_out.write(' '.join(map(str, edge)))
            edgelist_out.write('\n')
        for _ in range(num_edges_in_right_cluster):
            edge = [v + n for v in random.sample(range(n), r)]
            edgelist_out.write(' '.join(map(str, edge)))
            edgelist_out.write('\n')

        # Now, generate the edges between the clusters.
        # We will consider each possible split between left and right clusters individually
        for r_prime in range(1, r):
            hyplogging.logger.debug(f"Considering r_prime = {r_prime}.")

            # Get the number of possible edges with this split.
            possible_edges_between_clusters = scipy.special.comb(n, r_prime) * scipy.special.comb(n, r - r_prime)
            num_edges_between_clusters = np.random.binomial(possible_edges_between_clusters, q)
            hyplogging.logger.debug(f"Possible edges between clusters: {possible_edges_between_clusters}")
            hyplogging.logger.debug(f"Edges between clusters: {num_edges_between_clusters}")

            # Generate the edges
            for _ in range(num_edges_between_clusters):
                edge = random.sample(range(n), r_prime) + [v + n for v in random.sample(range(n), r - r_prime)]
                edgelist_out.write(' '.join(map(str, edge)))
                edgelist_out.write('\n')
//  [python]
def comb(n, k):
    """Return n choose k

    This function works on arrays, and will properly return a python integer
    object if the number is too large to be stored in a 64 bit integer.
    """
    # pylint: disable-msg=invalid-name
    res = np.rint(s.comb(n, k, False))
    if np.all(res < _MAX_INT_FLOAT):  # pylint: disable=no-else-return
        return res.astype(int)
    elif isinstance(n, abc.Iterable) or isinstance(k, abc.Iterable):
        broad = np.broadcast(np.asarray(n), np.asarray(k))
        res = np.empty(broad.shape, dtype=object)
        res.flat = [s.comb(n_, k_, True) for n_, k_ in broad]
        return res
    else:
        return s.comb(n, k, True)
//  [python]
def comb(n, k):
    """Return n choose k

    This function works on arrays, and will properly return a python integer
    object if the number is too large to be stored in a 64 bit integer.
    """
    # pylint: disable-msg=invalid-name
    res = np.rint(sps.comb(n, k, False))
    if np.all(res < _MAX_INT_FLOAT):  # pylint: disable=no-else-return
        return res.astype(int)
    elif isinstance(n, abc.Iterable) or isinstance(k, abc.Iterable):
        broad = np.broadcast(np.asarray(n), np.asarray(k))
        res = np.empty(broad.shape, dtype=object)
        res.flat = [sps.comb(n_, k_, True) for n_, k_ in broad]
        return res
    else:
        return sps.comb(n, k, True)
//  [python]
def _acombr(n, k):
    """Combinations with repetitions"""
    # pylint: disable-msg=invalid-name
    # This uses dynamic programming to compute everything
    num = s.comb(n + k - 1, k, exact=True)
    grid = np.zeros((num, n), dtype=int)
    memoized = {}

    # This recursion breaks if asking for numbers that are too large (stack
    # overflow), but the order to fill n and k is predictable, it may be better
    # to to use a for loop.
    def fill_region(n, k, region):
        """Recursively fill a region"""
        if n == 1:
            region[0, 0] = k
            return
        elif k == 0:
            region.fill(0)
            return
        if (n, k) in memoized:
            np.copyto(region, memoized[n, k])
            return
        memoized[n, k] = region
        o = 0
        for ki in range(k, -1, -1):
            n_ = n - 1
            k_ = k - ki
            m = s.comb(n_ + k_ -1, k_, exact=True)
            region[o : o + m, 0] = ki
            fill_region(n_, k_, region[o : o + m, 1:])
            o += m

    fill_region(n, k, grid)
    return grid
//  [python]
def _acombr(n, k):
    """Combinations with repetitions"""
    # pylint: disable-msg=invalid-name
    # This uses dynamic programming to compute everything
    num = sps.comb(n, k, repetition=True, exact=True)
    grid = np.zeros((num, n), dtype=int)
    memoized = {}

    # This recursion breaks if asking for numbers that are too large (stack
    # overflow), but the order to fill n and k is predictable, it may be better
    # to to use a for loop.
    def fill_region(n, k, region):
        """Recursively fill a region"""
        if n == 1:
            region[0, 0] = k
            return
        elif k == 0:
            region.fill(0)
            return
        if (n, k) in memoized:
            np.copyto(region, memoized[n, k])
            return
        memoized[n, k] = region
        o = 0
        for ki in range(k, -1, -1):
            n_ = n - 1
            k_ = k - ki
            m = sps.comb(n_, k_, repetition=True, exact=True)
            region[o : o + m, 0] = ki
            fill_region(n_, k_, region[o : o + m, 1:])
            o += m

    fill_region(n, k, grid)
    return grid
//  [python]
def BernsteinRef(u, p):
    """ Evaluates Bernsein basis functions defined on [-1,1]"""
    i = np.arange(p+1)
    ur = np.repeat(u, p+1).reshape((len(u), p+1))
    N = ((1-ur)**(p-i)*(1+ur)**i)*s.comb(p, i)/(2**p)
    N1 = ((1-ur)**(p-1-(i-1))*(1+ur)**(i-1))*s.comb(p-1, i-1)/(2**(p-1))
    N2 = ((1-ur)**(p-1-(i))*(1+ur)**(i))*s.comb(p-1, i)/(2**(p-1))
    dN = 0.5*p*(N1-N2)
    return N, dN
//  [python]
def BernsteinRef(u, p):
    """ Evaluates Bernsein basis functions defined on [-1,1]"""
    i = np.arange(p+1)
    ur = np.repeat(u, p+1).reshape((len(u), p+1))
    N = ((1-ur)**(p-i)*(1+ur)**i)*spe.comb(p, i)/(2**p)
    N1 = ((1-ur)**(p-1-(i-1))*(1+ur)**(i-1))*spe.comb(p-1, i-1)/(2**(p-1))
    N2 = ((1-ur)**(p-1-(i))*(1+ur)**(i))*spe.comb(p-1, i)/(2**(p-1))
    dN = 0.5*p*(N1-N2)
    return N, dN
//  [python]
def _acomb(n, k):
    """Combinations"""
    # pylint: disable-msg=invalid-name
    if k == 0:
        return np.zeros((1, n), bool)

    # This uses dynamic programming to compute everything
    num = s.comb(n, k, exact=True)
    grid = np.empty((num, n), dtype=bool)
    memoized = {}

    # This recursion breaks if asking for numbers that are too large (stack
    # overflow), but the order to fill n and k is predictable, it may be better
    # to to use a for loop.
    def fill_region(n, k, region):
        """Recursively fill a region"""
        if n <= k:
            region.fill(True)
            return
        elif k == 1:
            region.fill(False)
            np.fill_diagonal(region, True)
            return
        if (n, k) in memoized:
            np.copyto(region, memoized[n, k])
            return

        memoized[n, k] = region
        trues = s.comb(n - 1, k - 1, exact=True)
        region[:trues, 0] = True
        fill_region(n - 1, k - 1, region[:trues, 1:])
        region[trues:, 0] = False
        fill_region(n - 1, k, region[trues:, 1:])

    fill_region(n, k, grid)
    return grid
//  [python]
def _acomb(n, k):
    """Combinations"""
    # pylint: disable-msg=invalid-name
    if k == 0:
        return np.zeros((1, n), bool)

    # This uses dynamic programming to compute everything
    num = sps.comb(n, k, exact=True)
    grid = np.empty((num, n), dtype=bool)
    memoized = {}

    # This recursion breaks if asking for numbers that are too large (stack
    # overflow), but the order to fill n and k is predictable, it may be better
    # to to use a for loop.
    def fill_region(n, k, region):
        """Recursively fill a region"""
        if n <= k:
            region.fill(True)
            return
        elif k == 1:
            region.fill(False)
            np.fill_diagonal(region, True)
            return
        if (n, k) in memoized:
            np.copyto(region, memoized[n, k])
            return

        memoized[n, k] = region
        trues = sps.comb(n - 1, k - 1, exact=True)
        region[:trues, 0] = True
        fill_region(n - 1, k - 1, region[:trues, 1:])
        region[trues:, 0] = False
        fill_region(n - 1, k, region[trues:, 1:])

    fill_region(n, k, grid)
    return grid
//  [python]
def print_num_choices(opts):
    num_choices = 0
    for i in range(opts.props_per_name):
        num_choices += s.comb(opts.num_props, i + 1)
    possible_samples = ((num_choices) ** opts.num_names) * (
        opts.num_names + opts.num_props
    )
    print("number of possible samples: {:.0f}\n".format(possible_samples))
//  [python]
def print_num_choices(opts):
    num_choices = 0
    for i in range(opts.props_per_name):
        num_choices += scipy.special.comb(opts.num_props, i + 1)
    possible_samples = ((num_choices) ** opts.num_names) * (
        opts.num_names + opts.num_props
    )
    print("number of possible samples: {:.0f}\n".format(possible_samples))
//  [python]
def bernsteinPoly(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 bernsteinPoly(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 prob_Nsample(num_P, AN_ratio, sample_ratio):
    num_AN = int(num_P * AN_ratio)
    num_N = num_P - num_AN
    num_sample = int(num_P * sample_ratio)
    #     print(num_sample)
    num_C_P = s.comb(num_P, num_sample)
    #     print(num_C_P)
    num_C_N = s.comb(num_N, num_sample)
    #     print(num_C_N)
    return num_C_N / num_C_P
//  [python]
def prob_Nsample(num_P, AN_ratio, sample_ratio):
    num_AN = int(num_P * AN_ratio)
    num_N = num_P - num_AN
    num_sample = int(num_P * sample_ratio)
    #     print(num_sample)
    num_C_P = scipy.special.comb(num_P, num_sample)
    #     print(num_C_P)
    num_C_N = scipy.special.comb(num_N, num_sample)
    #     print(num_C_N)
    return num_C_N / num_C_P
//  [python]
def explain(self, incoming_instance, **kwargs):
        
        # convert incoming input to a standardized iml object
        instance = convert_to_instance(incoming_instance)
        match_instance_to_data(instance, self.data)

        assert len(self.data.groups) == self.P, "BruteForceExplainer does not support feature groups!"

        # find the feature groups we will test. If a feature does not change from its
        # current value then we know it doesn't impact the model
        self.varyingInds = self.varying_groups(instance.x)
        #self.varyingFeatureGroups = [self.data.groups[i] for i in self.varyingInds]
        self.M = len(self.varyingInds)

        phi = np.zeros((len(self.data.groups), self.D))
        phi_var = np.zeros((len(self.data.groups), self.D))
        x = instance.x
        masker_data = self.data.data
        masker = lambda x, mask: x * mask + masker_data * np.invert(mask)
        mask = np.zeros(self.P, dtype=np.bool)
        f = self.model.f
        for i in range(self.P):
            for s in powerset(set(range(self.P)).difference([i])):
                weight = 1 / (s.comb(self.P - 1, len(s)) * self.P)
                mask[:] = 0
                mask[list(s)] = 1
                f_without_i = f(masker(x, mask)).mean(0)
                mask[i] = 1
                f_with_i = f(masker(x, mask)).mean(0)
                phi[i,:] += weight * (f_with_i - f_without_i)

        if phi.shape[1] == 1:
            phi = phi[:,0]

        return phi
//  [python]
def explain(self, incoming_instance, **kwargs):
        
        # convert incoming input to a standardized iml object
        instance = convert_to_instance(incoming_instance)
        match_instance_to_data(instance, self.data)

        assert len(self.data.groups) == self.P, "BruteForceExplainer does not support feature groups!"

        # find the feature groups we will test. If a feature does not change from its
        # current value then we know it doesn't impact the model
        self.varyingInds = self.varying_groups(instance.x)
        #self.varyingFeatureGroups = [self.data.groups[i] for i in self.varyingInds]
        self.M = len(self.varyingInds)

        phi = np.zeros((len(self.data.groups), self.D))
        phi_var = np.zeros((len(self.data.groups), self.D))
        x = instance.x
        masker_data = self.data.data
        masker = lambda x, mask: x * mask + masker_data * np.invert(mask)
        mask = np.zeros(self.P, dtype=np.bool)
        f = self.model.f
        for i in range(self.P):
            for s in powerset(set(range(self.P)).difference([i])):
                weight = 1 / (scipy.special.comb(self.P - 1, len(s)) * self.P)
                mask[:] = 0
                mask[list(s)] = 1
                f_without_i = f(masker(x, mask)).mean(0)
                mask[i] = 1
                f_with_i = f(masker(x, mask)).mean(0)
                phi[i,:] += weight * (f_with_i - f_without_i)

        if phi.shape[1] == 1:
            phi = phi[:,0]

        return phi
//  [python]
def general_upperbound(func, mm, prob):
    """

    :param func:
    :param mm: alpha in RDP
    :param prob: sample probability
    :return: the upperbound in theorem 1 in 2019 ICML,could be applied for general case(including poisson distribution)
    k_approx = 100 k approximation is applied here
    """
    def cgf(x):
        return (x - 1) * func(x)

    if np.isinf(func(mm)):
        return np.inf
    if mm == 1 or mm == 0:
        return 0

    cur_k = np.minimum(50, mm - 1) # choose small k-approx for general upperbound (here is 50) in case of scipy-accuracy
    log_term_1 = mm * np.log(1 - prob)
    #logBin = utils.get_binom_coeffs(mm)
    log_term_2 = np.log(3) - func(mm) + mm * utils.stable_logsumexp_two(np.log(1 - prob), np.log(prob) + func(mm))
    neg_term_3 = [np.log(s.comb(mm,l)) + np.log(3) + (mm - l) * np.log(1 - prob) + l * np.log(prob) +
                  utils.stable_log_diff_exp((l - 1) * func(mm), cgf(l))[1] for l in
                  range(3, cur_k + 1)]
    neg_term_4 = np.log(mm*(mm - 1)/2) + 2 * np.log(prob) + (mm - 2) * np.log(
        1 - prob) + utils.stable_log_diff_exp(np.log(3) + func(mm), func(2))[1]
    neg_term_5 = np.log(2) + np.log(prob) + np.log(mm) + (mm - 1) * np.log(1 - prob)
    neg_term_6 = mm * np.log(1 - prob) + np.log(3) - func(mm)
    pos_term = utils.stable_logsumexp([log_term_1, log_term_2])
    neg_term_3.append(neg_term_4)
    neg_term_3.append(neg_term_5)
    neg_term_3.append(neg_term_6)
    neg_term = utils.stable_logsumexp(neg_term_3)
    bound = utils.stable_log_diff_exp(pos_term, neg_term)[1]
    return bound
//  [python]
def general_upperbound(func, mm, prob):
    """

    :param func:
    :param mm: alpha in RDP
    :param prob: sample probability
    :return: the upperbound in theorem 1 in 2019 ICML,could be applied for general case(including poisson distribution)
    k_approx = 100 k approximation is applied here
    """
    def cgf(x):
        return (x - 1) * func(x)

    if np.isinf(func(mm)):
        return np.inf
    if mm == 1 or mm == 0:
        return 0

    cur_k = np.minimum(50, mm - 1) # choose small k-approx for general upperbound (here is 50) in case of scipy-accuracy
    log_term_1 = mm * np.log(1 - prob)
    #logBin = utils.get_binom_coeffs(mm)
    log_term_2 = np.log(3) - func(mm) + mm * utils.stable_logsumexp_two(np.log(1 - prob), np.log(prob) + func(mm))
    neg_term_3 = [np.log(scipy.special.comb(mm,l)) + np.log(3) + (mm - l) * np.log(1 - prob) + l * np.log(prob) +
                  utils.stable_log_diff_exp((l - 1) * func(mm), cgf(l))[1] for l in
                  range(3, cur_k + 1)]
    neg_term_4 = np.log(mm*(mm - 1)/2) + 2 * np.log(prob) + (mm - 2) * np.log(
        1 - prob) + utils.stable_log_diff_exp(np.log(3) + func(mm), func(2))[1]
    neg_term_5 = np.log(2) + np.log(prob) + np.log(mm) + (mm - 1) * np.log(1 - prob)
    neg_term_6 = mm * np.log(1 - prob) + np.log(3) - func(mm)
    pos_term = utils.stable_logsumexp([log_term_1, log_term_2])
    neg_term_3.append(neg_term_4)
    neg_term_3.append(neg_term_5)
    neg_term_3.append(neg_term_6)
    neg_term = utils.stable_logsumexp(neg_term_3)
    bound = utils.stable_log_diff_exp(pos_term, neg_term)[1]
    return bound
//  [python]
def _samlmularge(x, nmom=5):
    try:
        x = np.asarray(x, dtype=np.float64)
        n = len(x)
        x.sort()
    except ValueError:
        raise ValueError("Input data to estimate L-moments must be numeric.")

    if nmom <= 0:
        raise ValueError("Invalid number of sample L-moments")

    if n < nmom:
        raise ValueError("Insufficient length of data for specified nmoments")

    # Calculate first order
    lm = [np.sum(x) / s.comb(n, 1, exact=True)]

    if nmom == 1:
        return lm[0]

    # Setup comb table, where comb[i][x] refers to comb(x,i)
    comb = []
    for i in range(1, nmom):
        comb.append([])
        for j in range(n):
            comb[-1].append(s.comb(j, i, exact=True))

    for mom in range(2, nmom + 1):
        coefl = 1.0 / mom * 1.0 / s.comb(n, mom, exact=True)
        xtrans = []
        for i in range(0, n):
            coeftemp = []
            for j in range(0, mom):
                coeftemp.append(1)

            for j in range(0, mom - 1):
                coeftemp[j] = coeftemp[j] * comb[mom - j - 2][i]

            for j in range(1, mom):
                coeftemp[j] = coeftemp[j] * comb[j - 1][n - i - 1]

            for j in range(0, mom):
                coeftemp[j] = coeftemp[j] * s.comb(mom - 1, j, exact=True)

            for j in range(0, int(0.5 * mom)):
                coeftemp[j * 2 + 1] = -coeftemp[j * 2 + 1]
            coeftemp = sum(coeftemp)
            xtrans.append(x[i] * coeftemp)

        if mom > 2:
            lm.append(coefl * sum(xtrans) / lm[1])
        else:
            lm.append(coefl * sum(xtrans))
    return lm
//  [python]
def _samlmularge(x, nmom=5):
    try:
        x = np.asarray(x, dtype=np.float64)
        n = len(x)
        x.sort()
    except ValueError:
        raise ValueError("Input data to estimate L-moments must be numeric.")

    if nmom <= 0:
        raise ValueError("Invalid number of sample L-moments")

    if n < nmom:
        raise ValueError("Insufficient length of data for specified nmoments")

    # Calculate first order
    lm = [np.sum(x) / sp.comb(n, 1, exact=True)]

    if nmom == 1:
        return lm[0]

    # Setup comb table, where comb[i][x] refers to comb(x,i)
    comb = []
    for i in range(1, nmom):
        comb.append([])
        for j in range(n):
            comb[-1].append(sp.comb(j, i, exact=True))

    for mom in range(2, nmom + 1):
        coefl = 1.0 / mom * 1.0 / sp.comb(n, mom, exact=True)
        xtrans = []
        for i in range(0, n):
            coeftemp = []
            for j in range(0, mom):
                coeftemp.append(1)

            for j in range(0, mom - 1):
                coeftemp[j] = coeftemp[j] * comb[mom - j - 2][i]

            for j in range(1, mom):
                coeftemp[j] = coeftemp[j] * comb[j - 1][n - i - 1]

            for j in range(0, mom):
                coeftemp[j] = coeftemp[j] * sp.comb(mom - 1, j, exact=True)

            for j in range(0, int(0.5 * mom)):
                coeftemp[j * 2 + 1] = -coeftemp[j * 2 + 1]
            coeftemp = sum(coeftemp)
            xtrans.append(x[i] * coeftemp)

        if mom > 2:
            lm.append(coefl * sum(xtrans) / lm[1])
        else:
            lm.append(coefl * sum(xtrans))
    return lm
//  [python]
def hypergeometric(population, population_successes, sample, sample_successes):
    return (s.comb(population_successes, sample_successes) *
            s.comb(population - population_successes, sample - sample_successes)) / \
           s.comb(population, sample)
//  [python]
def hypergeometric(population, population_successes, sample, sample_successes):
    return (scipy.special.comb(population_successes, sample_successes) *
            scipy.special.comb(population - population_successes, sample - sample_successes)) / \
           scipy.special.comb(population, sample)
//  [python]
def fast_k_subsample_upperbound(func, mm, prob, k):
    """

     :param func:
     :param mm:
     :param prob: sample probability
     :param k: approximate term
     :return: k-term approximate upper bound in therorem 11 in ICML-19
     """
    def cgf(x):
        return (x - 1) * func(x)

    if np.isinf(func(mm)):
        return np.inf
    if mm == 1:
        return 0
    #logBin = utils.get_binom_coeffs(mm)
    cur_k = np.minimum(k, mm - 1)
    if (2 * cur_k) >= mm:
        exact_term_1 = (mm - 1) * np.log(1 - prob) + np.log(mm * prob - prob + 1)
        exact_term_2 = [np.log(s.comb(mm,l))  + (mm - l) * np.log(1 - prob) + l * np.log(prob) + cgf(l) for l in
                        range(2, mm + 1)]
        exact_term_2.append(exact_term_1)
        bound = utils.stable_logsumexp(exact_term_2)
        return bound

    s, mag1 = utils.stable_log_diff_exp(0, -func(mm - cur_k))
    new_log_term_1 = np.log(1 - prob) * mm + mag1
    new_log_term_2 = -func(mm - cur_k) + mm * utils.stable_logsumexp_two(np.log(1 - prob),
                                                                         np.log(prob) + func(mm - cur_k))
    new_log_term_3 = [np.log(s.comb(mm,l)) + (mm - l) * np.log(1 - prob) + l * np.log(prob) +
                      utils.stable_log_diff_exp((l - 1) * func(mm - cur_k), cgf(l))[1] for l in
                      range(2, cur_k + 1)]
    if len(new_log_term_3) > 0:
        new_log_term_3 = utils.stable_logsumexp(new_log_term_3)
    else:
        return utils.stable_logsumexp_two(new_log_term_1, new_log_term_2)
    new_log_term_4 = [np.log(s.comb(mm,mm-l)) + (mm - l) * np.log(1 - prob) + l * np.log(prob) +
                      utils.stable_log_diff_exp(cgf(l), (l - 1) * func(mm - cur_k))[1] for l in
                      range(mm - cur_k + 1, mm + 1)]
    new_log_term_4.append(new_log_term_1)
    new_log_term_4.append(new_log_term_2)
    new_log_term_4 = utils.stable_logsumexp(new_log_term_4)
    s, new_log_term_5 = utils.stable_log_diff_exp(new_log_term_4, new_log_term_3)
    new_bound = new_log_term_5
    return new_bound
//  [python]
def fast_k_subsample_upperbound(func, mm, prob, k):
    """

     :param func:
     :param mm:
     :param prob: sample probability
     :param k: approximate term
     :return: k-term approximate upper bound in therorem 11 in ICML-19
     """
    def cgf(x):
        return (x - 1) * func(x)

    if np.isinf(func(mm)):
        return np.inf
    if mm == 1:
        return 0
    #logBin = utils.get_binom_coeffs(mm)
    cur_k = np.minimum(k, mm - 1)
    if (2 * cur_k) >= mm:
        exact_term_1 = (mm - 1) * np.log(1 - prob) + np.log(mm * prob - prob + 1)
        exact_term_2 = [np.log(scipy.special.comb(mm,l))  + (mm - l) * np.log(1 - prob) + l * np.log(prob) + cgf(l) for l in
                        range(2, mm + 1)]
        exact_term_2.append(exact_term_1)
        bound = utils.stable_logsumexp(exact_term_2)
        return bound

    s, mag1 = utils.stable_log_diff_exp(0, -func(mm - cur_k))
    new_log_term_1 = np.log(1 - prob) * mm + mag1
    new_log_term_2 = -func(mm - cur_k) + mm * utils.stable_logsumexp_two(np.log(1 - prob),
                                                                         np.log(prob) + func(mm - cur_k))
    new_log_term_3 = [np.log(scipy.special.comb(mm,l)) + (mm - l) * np.log(1 - prob) + l * np.log(prob) +
                      utils.stable_log_diff_exp((l - 1) * func(mm - cur_k), cgf(l))[1] for l in
                      range(2, cur_k + 1)]
    if len(new_log_term_3) > 0:
        new_log_term_3 = utils.stable_logsumexp(new_log_term_3)
    else:
        return utils.stable_logsumexp_two(new_log_term_1, new_log_term_2)
    new_log_term_4 = [np.log(scipy.special.comb(mm,mm-l)) + (mm - l) * np.log(1 - prob) + l * np.log(prob) +
                      utils.stable_log_diff_exp(cgf(l), (l - 1) * func(mm - cur_k))[1] for l in
                      range(mm - cur_k + 1, mm + 1)]
    new_log_term_4.append(new_log_term_1)
    new_log_term_4.append(new_log_term_2)
    new_log_term_4 = utils.stable_logsumexp(new_log_term_4)
    s, new_log_term_5 = utils.stable_log_diff_exp(new_log_term_4, new_log_term_3)
    new_bound = new_log_term_5
    return new_bound
//  [python]
def choose(n, k):
    return scipy.misc.comb(n, k)
//  [python]
def choose(n, k):
    return scipy.special.comb(n, k)
//  [python]
def _samlmusmall(x, nmom=5):
    try:
        x = np.asarray(x, dtype=np.float64)
        n = len(x)
        x = sorted(x)
    except ValueError:
        raise ValueError("Input data to estimate L-moments must be numeric.")

    if nmom <= 0 or nmom > 5:
        raise ValueError("Invalid number of sample L-moments")

    if n < nmom:
        raise ValueError("Insufficient length of data for specified nmoments")

    # First L-moment

    l1 = np.sum(x) / s.comb(n, 1, exact=True)

    if nmom == 1:
        return l1

    # Second L-moment

    comb1 = range(n)
    coefl2 = 0.5 / s.comb(n, 2, exact=True)
    sum_xtrans = sum([(comb1[i] - comb1[n - i - 1]) * x[i] for i in range(n)])
    l2 = coefl2 * sum_xtrans

    if nmom == 2:
        return [l1, l2]

    # Third L-moment

    comb3 = [s.comb(i, 2, exact=True) for i in range(n)]
    coefl3 = 1.0 / 3.0 / s.comb(n, 3, exact=True)
    sum_xtrans = sum([(comb3[i] - 2 * comb1[i] * comb1[n - i - 1] + comb3[n - i - 1]) * x[i] for i in range(n)])
    l3 = coefl3 * sum_xtrans / l2

    if nmom == 3:
        return [l1, l2, l3]

    # Fourth L-moment

    comb5 = [s.comb(i, 3, exact=True) for i in range(n)]
    coefl4 = 0.25 / s.comb(n, 4, exact=True)
    sum_xtrans = sum(
        [(comb5[i] - 3 * comb3[i] * comb1[n - i - 1] + 3 * comb1[i] * comb3[n - i - 1] - comb5[n - i - 1]) * x[i]
         for i in range(n)])
    l4 = coefl4 * sum_xtrans / l2

    if nmom == 4:
        return [l1, l2, l3, l4]

    # Fifth L-moment

    comb7 = [s.comb(i, 4, exact=True) for i in range(n)]
    coefl5 = 0.2 / s.comb(n, 5, exact=True)
    sum_xtrans = sum(
        [(comb7[i] - 4 * comb5[i] * comb1[n - i - 1] + 6 * comb3[i] * comb3[n - i - 1] -
          4 * comb1[i] * comb5[n - i - 1] + comb7[n - i - 1]) * x[i]
         for i in range(n)])
    l5 = coefl5 * sum_xtrans / l2

    return [l1, l2, l3, l4, l5]
//  [python]
def _samlmusmall(x, nmom=5):
    try:
        x = np.asarray(x, dtype=np.float64)
        n = len(x)
        x = sorted(x)
    except ValueError:
        raise ValueError("Input data to estimate L-moments must be numeric.")

    if nmom <= 0 or nmom > 5:
        raise ValueError("Invalid number of sample L-moments")

    if n < nmom:
        raise ValueError("Insufficient length of data for specified nmoments")

    # First L-moment

    l1 = np.sum(x) / sp.comb(n, 1, exact=True)

    if nmom == 1:
        return l1

    # Second L-moment

    comb1 = range(n)
    coefl2 = 0.5 / sp.comb(n, 2, exact=True)
    sum_xtrans = sum([(comb1[i] - comb1[n - i - 1]) * x[i] for i in range(n)])
    l2 = coefl2 * sum_xtrans

    if nmom == 2:
        return [l1, l2]

    # Third L-moment

    comb3 = [sp.comb(i, 2, exact=True) for i in range(n)]
    coefl3 = 1.0 / 3.0 / sp.comb(n, 3, exact=True)
    sum_xtrans = sum([(comb3[i] - 2 * comb1[i] * comb1[n - i - 1] + comb3[n - i - 1]) * x[i] for i in range(n)])
    l3 = coefl3 * sum_xtrans / l2

    if nmom == 3:
        return [l1, l2, l3]

    # Fourth L-moment

    comb5 = [sp.comb(i, 3, exact=True) for i in range(n)]
    coefl4 = 0.25 / sp.comb(n, 4, exact=True)
    sum_xtrans = sum(
        [(comb5[i] - 3 * comb3[i] * comb1[n - i - 1] + 3 * comb1[i] * comb3[n - i - 1] - comb5[n - i - 1]) * x[i]
         for i in range(n)])
    l4 = coefl4 * sum_xtrans / l2

    if nmom == 4:
        return [l1, l2, l3, l4]

    # Fifth L-moment

    comb7 = [sp.comb(i, 4, exact=True) for i in range(n)]
    coefl5 = 0.2 / sp.comb(n, 5, exact=True)
    sum_xtrans = sum(
        [(comb7[i] - 4 * comb5[i] * comb1[n - i - 1] + 6 * comb3[i] * comb3[n - i - 1] -
          4 * comb1[i] * comb5[n - i - 1] + comb7[n - i - 1]) * x[i]
         for i in range(n)])
    l5 = coefl5 * sum_xtrans / l2

    return [l1, l2, l3, l4, l5]
//  [python]
def test_errprint(self):
        a = special.errprint()
        b = 1-a  # a is the state 1-a inverts state
        c = special.errprint(b)  # returns last state 'a'
        assert_equal(a,c)
        d = special.errprint(a)  # returns to original state
        assert_equal(d,b)
//  [python]
def test_errprint(self):
        a = special.seterr(all='raise')
        b = 1-a  # a is the state 1-a inverts state
        c = special.seterr(b)  # returns last state 'a'
        assert_equal(a,c)
        d = special.seterr(a)  # returns to original state
        assert_equal(d,b)
//  [python]
def test_errprint():
    with suppress_warnings() as sup:
        sup.filter(DeprecationWarning, "`errprint` is deprecated!")
        flag = sc.errprint(True)

    try:
        assert_(isinstance(flag, bool))
        with pytest.warns(sc.SpecialFunctionWarning):
            sc.loggamma(0)
    finally:
        with suppress_warnings() as sup:
            sup.filter(DeprecationWarning, "`errprint` is deprecated!")
            sc.errprint(flag)
//  [python]
def test_errprint():
    with suppress_warnings() as sup:
        sup.filter(DeprecationWarning, "`errprint` is deprecated!")
        flag = sc.seterr(all='raise')

    try:
        assert_(isinstance(flag, dict))
        with pytest.warns(sc.SpecialFunctionWarning):
            sc.loggamma(0)
    finally:
        with suppress_warnings() as sup:
            sup.filter(DeprecationWarning, "`errprint` is deprecated!")
            sc.seterr(**flag)
//  [python]
def significance(graph: nx.Graph, communities: object, **kwargs: dict) -> object:
    """Significance estimates how likely a partition of dense communities appear in a random graph.

    :param graph: a networkx/igraph object
    :param communities: NodeClustering object
    :return: FitnessResult object

    Example:

    >>> from cdlib.algorithms import louvain
    >>> from cdlib import evaluation
    >>> g = nx.karate_club_graph()
    >>> communities = louvain(g)
    >>> mod = evaluation.significance(g,communities)

    :References:

    1. Traag, V. A., Aldecoa, R., & Delvenne, J. C. (2015). `Detecting communities using asymptotical surprise. <https://link.aps.org/doi/10.1103/PhysRevE.92.022816/>`_ Physical Review E, 92(2), 022816.
    """
    graph = convert_graph_formats(graph, nx.Graph)
    m = graph.number_of_edges()

    binom = s.comb(m, 2, exact=True)
    p = m / binom

    q = 0

    for community in communities.communities:
        try:
            c = nx.subgraph(graph, community)
            nc = c.number_of_nodes()
            mc = c.number_of_edges()

            binom_c = s.comb(nc, 2, exact=True)
            pc = mc / binom_c

            q += binom_c * (pc * np.log(pc / p) + (1 - pc) * np.log((1 - pc) / (1 - p)))
        except ZeroDivisionError:
            pass
    return FitnessResult(score=q)