def analyse_suboptimal_arm_pulls(self):
        # Compute deltas and theoretical upper bound of playing each sub-optimal arm.
        self.best_arm = mh.get_maximum_index(self.true_means)
        mean_of_best_arm = self.true_means[self.best_arm]

        for i in range(self.K):
            self.deltas[i] = mean_of_best_arm - self.true_means[i]

        del_sq_invs = mh.get_instance_dependent_square_inverses(
            self.deltas, self.best_arm)

        addi_constant = rvh.func_of_pi(add=1, power=2, mult=1 / 3)

        time_series = np.arange(self.T + 1)

        logarithmic_time_series = rvh.natural_logarithm(time_series)

        a = np.array(del_sq_invs)
        del_sq_inv_row_matrix = np.reshape(a, (1, -1))
        logarithmic_time_series_column_matrix = np.reshape(
            logarithmic_time_series, (-1, 1))

        matrix = np.dot(logarithmic_time_series_column_matrix,
                        del_sq_inv_row_matrix)

        self.theoretical_bounds_arm_pulls = matrix + addi_constant
    def analyse_common_stats(self):
        # Compute deltas and theoretical upper bound of regret of UCB1.
        self.best_arm = mh.get_maximum_index(self.true_means)
        mean_of_best_arm = self.true_means[self.best_arm]

        for i in range(self.K):
            self.deltas[i] = mean_of_best_arm - self.true_means[i]

        sum_del_inv, sum_del = mh.get_instance_dependent_values(
            self.best_arm, self.deltas)

        mult_constant, addi_constant = mh.get_theoretical_constants(
            sum_del_inv, sum_del)

        time_series = np.arange(self.T + 1)
        self.cum_regret_theo_bound = mult_constant * rvh.natural_logarithm(
            time_series) + addi_constant
        self.cum_optimal_reward = time_series * mean_of_best_arm