def knowledge_reconstruction_examination(self):
        """
        Perform the knowledge reconstruction examination.
        :return: Tuple containing the useful population, useless population, and cluster centroids
        """
        clusters = self.ps  # set historical PS set as clusters
        Nc = self.C_SIZE  # set final nr of clusters
        size = len(self.ps)  # set size iteration to length of cluster
        run_counter = 0  # counter variable to give unique key

        # while there are still clusters to be condensed
        while size > Nc:

            counter = 0
            min_distance = None
            min_distance_index = []

            # get clusters that are closest to each other by calculating the euclidean distance
            for keys_i in clusters.keys():
                for keys_j in clusters.keys():
                    if (
                        clusters[keys_i]["solutions"]
                        is not clusters[keys_j]["solutions"]
                    ):

                        dst = euclidean_distance(
                            clusters[keys_i]["centroid"],
                            clusters[keys_j]["centroid"],
                        )

                        if min_distance == None:
                            min_distance = dst
                            min_distance_index = [keys_i, keys_j]
                        elif dst < min_distance:
                            min_distance = dst

                            min_distance_index = [keys_i, keys_j]

                        counter += 1

            # merge closest clusters
            for solution in clusters[min_distance_index[1]]["solutions"]:
                clusters[min_distance_index[0]]["solutions"].append(solution)

            # calculate new centroid for merged cluster
            clusters[min_distance_index[0]][
                "centroid"
            ] = self.calculate_cluster_centroid(
                clusters[min_distance_index[0]]["solutions"]
            )

            # remove cluster that was merged
            del clusters[min_distance_index[1]]

            size -= 1
            run_counter += 1

        c = []  # list of centroids
        pop_useful = []
        pop_useless = []

        # get centroids of clusters
        for key in clusters.keys():
            c.append(clusters[key]["centroid"])

        # create pymoo population objected to evaluate centroid solutions
        centroid_pop = Population.new("X", c)

        # evaluate centroids
        self.evaluator.eval(self.problem, centroid_pop)

        # do non-dominated sorting on centroid solutions
        ranking = NonDominatedSorting().do(centroid_pop.get("F"), return_rank=True)[-1]

        # add the individuals from the clusters with the best objective values to the useful population the rest is useless :(

        for idx, rank in enumerate(ranking):
            if rank == 0:
                for key in clusters.keys():
                    if centroid_pop[idx].X == clusters[key]["centroid"]:
                        for cluster_individual in clusters[key]["solutions"]:
                            pop_useful.append(cluster_individual)
            else:
                for key in clusters.keys():
                    if centroid_pop[idx].X == clusters[key]["centroid"]:
                        for cluster_individual in clusters[key]["solutions"]:
                            pop_useless.append(cluster_individual)

        # return useful and useless population and the centroid solutions
        return pop_useful, pop_useless, c

        Perform the knowledge reconstruction examination.
        :return: Tuple containing the useful population, useless population, and cluster centroids
        
pymoo/algorithms/moo/kgb.py