def compute_rejection_stats(self, T=32, delta=0.1, c_fp=1, c_fn=1, c_r=-1,
                                verbose=False):
        """Add reject option into the unsupervised detector. 
           This comes with guarantees: an estimate of the expected
           rejection rate (return_rejectrate=True), an upper
           bound of the rejection rate (return_ub_rejectrate= True),
           and an upper bound on the cost (return_ub_cost=True).
           
        Parameters
        ----------
        T: int, optional(default=32)
           It allows to set the rejection threshold to 1-2exp(-T).
           The higher the value of T, the more rejections are made.
            
        delta: float, optional (default = 0.1)
               The upper bound rejection rate holds with probability 1-delta.
                       
        c_fp, c_fn, c_r: floats (positive),
                         optional (default = [1,1, contamination])
                         costs for false positive predictions (c_fp),
                         false negative predictions (c_fn) and rejections (c_r).
                         
        verbose: bool, optional (default = False)
                 If true, it prints the expected rejection rate, the upper
                 bound rejection rate, and the upper bound of the cost.

        Returns
        -------
        expected_rejection_rate:   float, the expected rejection rate;
        upperbound_rejection_rate: float, the upper bound for the rejection rate
                                   satisfied with probability 1-delta;
        upperbound_cost:           float, the upper bound for the cost;
        """

        check_is_fitted(self, ['decision_scores_', 'threshold_', 'labels_'])

        if c_r < 0:
            c_r = self.contamination

        if delta <= 0 or delta >= 1:
            delta = 0.1

        # Computing the expected rejection rate
        n = len(self.decision_scores_)
        n_gamma_minus1 = int(n * self.contamination) - 1
        argsmin = (n_gamma_minus1, n, 1 - np.exp(-T))
        argsmax = (n_gamma_minus1, n, np.exp(-T))
        q1 = root_scalar(lambda p, k, n, C: binom.cdf(k, n, p) - C,
                         bracket=[0, 1], method='brentq', args=argsmin).root
        q2 = root_scalar(lambda p, k, n, C: binom.cdf(k, n, p) - C,
                         bracket=[0, 1], method='brentq', args=argsmax).root
        expected_reject_rate = q2 - q1

        # Computing the upper bound for the rejection rate
        right_mar = (-self.contamination * (n + 2) + n + 1) / n + (
                    T * (n + 2)) / (np.sqrt(2 * n ** 3 * T))
        right_mar = min(1, right_mar)
        left_mar = (
                (2 + n * (1 - self.contamination) * (n + 1)) / n ** 2
                - np.sqrt(
            0.5 * n ** 5 * (
                    2 * n * (
                    -3 * self.contamination ** 2
                    - 2 * n * (1 - self.contamination) ** 2
                    + 4 * self.contamination - 3
            )
                    + T * (n + 2) ** 2 - 8
            )
        ) / n ** 4
        )
        left_mar = max(0, left_mar)
        add_term = 2 * np.sqrt(np.log(2 / delta) / (2 * n))
        upperbound_rejectrate = right_mar - left_mar + add_term

        # Computing the upper bound for the cost function
        n_gamma_minus1 = int(n * self.contamination) - 1
        argsmin = (n_gamma_minus1, n, 1 - np.exp(-T))
        argsmax = (n_gamma_minus1, n, np.exp(-T))
        q1 = root_scalar(lambda p, k, n, C: binom.cdf(k, n, p) - C,
                         bracket=[0, 1], method='brentq', args=argsmin).root
        q2 = root_scalar(lambda p, k, n, C: binom.cdf(k, n, p) - C,
                         bracket=[0, 1], method='brentq', args=argsmax).root
        upperbound_cost = np.min([self.contamination, q1]) * c_fp + np.min(
            [1 - q2, self.contamination]) * c_fn + (q2 - q1) * c_r

        if verbose:
            print("Expected rejection rate: ",
                  np.round(expected_reject_rate, 4), '%')
            print("Upper bound rejection rate: ",
                  np.round(upperbound_rejectrate, 4), '%')
            print("Upper bound cost: ", np.round(upperbound_cost, 4))

        return expected_reject_rate, upperbound_rejectrate, upperbound_cost
Add reject option into the unsupervised detector. 
           This comes with guarantees: an estimate of the expected
           rejection rate (return_rejectrate=True), an upper
           bound of the rejection rate (return_ub_rejectrate= True),
           and an upper bound on the cost (return_ub_cost=True).
           
        Parameters
        ----------
        T: int, optional(default=32)
           It allows to set the rejection threshold to 1-2exp(-T).
           The higher the value of T, the more rejections are made.
            
        delta: float, optional (default = 0.1)
               The upper bound rejection rate holds with probability 1-delta.
                       
        c_fp, c_fn, c_r: floats (positive),
                         optional (default = [1,1, contamination])
                         costs for false positive predictions (c_fp),
                         false negative predictions (c_fn) and rejections (c_r).
                         
        verbose: bool, optional (default = False)
                 If true, it prints the expected rejection rate, the upper
                 bound rejection rate, and the upper bound of the cost.

        Returns
        -------
        expected_rejection_rate:   float, the expected rejection rate;
        upperbound_rejection_rate: float, the upper bound for the rejection rate
                                   satisfied with probability 1-delta;
        upperbound_cost:           float, the upper bound for the cost;
        
pyod/models/base.py