//  [python]
def estimate_all(self, perturbed_datas, selected_indexs):
        total_n = len(perturbed_datas)
        selected_i = 0
        all_results = []
        all_configs = []
        all_multiples = []
        for group_index in range(len(self.group_indexs)):
            (user_start, user_end) = self.group_indexs[group_index]
            old_selected_i = selected_i
            while selected_i < len(selected_indexs) and selected_indexs[selected_i] < user_end:
                selected_i += 1

            if selected_i > old_selected_i:
                selected_perturbed_datas = perturbed_datas[old_selected_i:selected_i]
                config_n = len(selected_perturbed_datas)
                (attr_config, layer_config) = self.group_configs[group_index]
                group_fos = self.group_fos[group_index]
                if self.args.layer_style == 'al':
                    all_attrs = []
                    for i in range(len(attr_config)):
                        for j in range(len(attr_config[i])):
                            all_attrs.append(attr_config[i][j])

                    all_heights = [range(self.tree_heights[x]) for x in all_attrs]
                    all_all_layers = itertools.product(*all_heights)

                    cluster_heights = [range(reduce(lambda x, y: x * y, [self.tree_heights[x] for x in attr_config[i]])) for i in range(len(attr_config))]
                    report_counts = itertools.product(*cluster_heights)
                    for layer_config in all_all_layers:
                        report_count = next(report_counts)
                        exist_star = False
                        for count in report_count:
                            if count == 0:
                                exist_star = True
                                break
                        # some report does not contribute info, which is prohibited
                        if exist_star:
                            continue

                        data_to_estimate = [[0 for _ in range(len(attr_config))] for _ in
                                            range(len(selected_perturbed_datas))]
                        for i in range(len(selected_perturbed_datas)):
                            for j in range(len(attr_config)):
                                data_to_estimate[i][j] = selected_perturbed_datas[i][j][report_count[j] - 1]
                        fos = []
                        for i in range(len(attr_config)):
                            fos.append(group_fos[i][report_count[i] - 1])
                        results = self.estimate_tree(data_to_estimate, attr_config, layer_config, fos)
                        all_results.append(results)
                        all_configs.append((attr_config, layer_config))
                        all_multiples.append(total_n / config_n)
                else:
                    fos = [group_fos[i][0] for i in range(len(group_fos))]
                    data_to_estimate = [[0 for _ in range(len(attr_config))] for _ in range(len(selected_perturbed_datas))]
                    for i in range(len(selected_perturbed_datas)):
                        for j in range(len(attr_config)):
                            data_to_estimate[i][j] = selected_perturbed_datas[i][j][0]
                    results = self.estimate_tree(data_to_estimate, attr_config, layer_config, fos)
                    all_results.append(results)
                    all_configs.append((attr_config, layer_config))
                    all_multiples.append(total_n / config_n)
        return all_results, all_configs, all_multiples